2tic:

Below is some code that shows how to encrypt\decrypt data consisting of multiple 64bit (8 byte) blocks. To properly process data with a length that is not a multiple of 8 bytes, it is neccessary to pad the data at the end, so that its length becomes a multiple of 8 bytes.

But I don't know, which padding method is best used. There is a

very nice article on block cipher operating modes at wikipedia. Among others it describes the following teqnique:

Slightly more complex is the original DES method, which is to add a single one bit, followed by enough zero bits to fill out the block; if the message ends on a block boundary, a whole padding block will be added.

Maybe Laszlo can answer if this would be a good choice.

The code below demonstrates the weakness (please note Laszlo's objection below regarding "weakness"; it rather is a property) of using XTEA (block ciphers in general) in ECB mode:

The disadvantage of this method is that identical plaintext blocks are encrypted into identical ciphertext blocks; thus, it does not hide data patterns well.

So working on using it in CBC mode seems mandatory to me.

#NoEnv
SetBatchLines -1
MCode(ByRef code, hex) { ; allocate memory and write Machine Code there
VarSetCapacity(code,StrLen(hex)//2)
Loop % StrLen(hex)//2
NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char")
}
MCode(enc, "5589E55383EC148B450C8B008945F88B450C83C0048B008945F4C745EC00000000C745E8B979379EC745F0000000008B45F0"
. "3B4508737D8B45F489C2C1E2048B45F4C1E80531D089C3035DF48B45EC83E0038D0C85000000008B55108B45EC03041189DA31C28D45F"
. "801108B55E88D45EC01108B45F889C2C1E2048B45F8C1E80531D089C3035DF88B45ECC1E80B83E0038D0C85000000008B55108B45EC03"
. "041189DA31C28D45F401108D45F0FF00E97BFFFFFF8B550C8B45F889028B550C83C2048B45F4890283C4145B5DC3")
MCode(dec, "5589E55383EC148B450C8B008945F88B450C83C0048B008945F4C745ECB979379E8B45EC0FAF45088945E8C745F000000000"
. "8B45F03B4508737D8B45F889C2C1E2048B45F8C1E80531D089C3035DF88B45E8C1E80B83E0038D0C85000000008B55108B45E80304118"
. "9DA31C28D45F429108B55EC8D45E829108B45F489C2C1E2048B45F4C1E80531D089C3035DF48B45E883E0038D0C85000000008B55108B"
. "45E803041189DA31C28D45F829108D45F0FF00E97BFFFFFF8B550C8B45F889028B550C83C2048B45F4890283C4145B5DC3")
MCode(k, 11111111222222223333333344444444) ; 128 bit key
v =
( Join
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!
Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny !!!Tiny 1KB
)
len := StrLen(v)
Loop % len/8
DllCall(&enc, "int",64, "uint",&v+(A_Index-1)*8, "uint",&k)
MsgBox % v
;ReadMemory("output.enc", &v, len)
;FileGetSize, len, output.enc
;WriteMemory("output.enc", v, len)
Loop % len/8
DllCall(&dec, "int",64, "uint",&v+(A_Index-1)*8, "uint",&k)
MsgBox % v

Using

Sean's FileHelper disk I/O could be done by adding the following code between encryption and decription:

ReadMemory("output.enc", &v, StrLen(v))
FileGetSize, nSize, output.enc
WriteMemory("output.enc", v, nSize)

2Laszlo:

Would the following code give us cryptographically secure initialization vectors for CBC mode?

MCode(k, 11111111222222223333333344444444)
; create 64 bit initialisation vector
Random, iv1
Random, iv2
VarSetCapacity(iv, 8)
NumPut(iv1, iv, 0, "UInt"), NumPut(iv2, iv, 4, "UInt")
DllCall(&enc, int,64, uint,&iv, uint,&k)

Edit 20070921: Added a remark regarding "weakness"

Edit 20070922: Changed code to correctly work for disk I/O