(*--------------------------------------------------------------------------------------------------- Implementation of the VMPC Stream Cipher and the VMPC-MAC Authenticated Encryption Scheme in ASSEMBLER embodied in the Pascal/Delphi environment, using the "register" calling convention Author of the algorithms: Bartosz Zoltak Author of the implementation: Bartosz Zoltak www.vmpcfunction.com ----------------------------------------------------------------------------------------------------- ----------------------- Usage of the algorithms: ---------------------------------------------------- ----------------------------------------------------------------------------------------------------- var Key, Vector : array[0..63] of byte; Message : array[0..999] of byte; MessageMAC : array[0..19] of byte; Encryption: VMPCInitKey_ASM(Klucz, Wektor, 16, 16); VMPCEncrypt_ASM(Wiadomosc, 1000); Decryption: VMPCInitKey_ASM(Klucz, Wektor, 16, 16); VMPCEncrypt_ASM(Wiadomosc, 1000); (the VMPCEncrypt_ASM procedure is used for both encryption and decryption). Authenticated Encryption (with the MAC tag): VMPCInitKey_ASM(Klucz, Wektor, 16, 16); VMPCInitMAC_ASM; VMPCEncryptMAC_ASM(Wiadomosc, 1000); VMPCOutputMAC_ASM; //The MAC tag is saved in the 20-byte "MAC" table Move(MAC, WiadomoscMAC, 20); //Save the generated MAC tag in the "MessageMAC" table Decryption and verification of the MAC tag: VMPCInitKey_ASM(Klucz, Wektor, 16, 16); VMPCInitMAC_ASM; VMPCDecryptMAC_ASM(Wiadomosc, 1000); VMPCOutputMAC_ASM; //The MAC tag is saved in the 20-byte "MAC" table If the 20-byte tables "MAC" and "MessageMAC" are identical, the message was correctly decrypted - the correct key was used and the message was not corrupted. ---------------------------------------------------------------------------------------------------- The VMPCInitKey_ASM / VMPCInitKey16_ASM functions (employing the VMPC-KSA3 key initialization algorithm) provide higher security level but about 1/3 lower efficiency. than the basic VMPCInitKeyBASIC_ASM / VMPCInitKey16BASIC_ASM functions. If only the system efficiency allows, the author recommends to use the VMPCInitKey_ASM / VMPCInitKey16_ASM functions. At the same time the VMPCInitKeyBASIC_ASM / VMPCInitKey16BASIC_ASM functions also remain secure. ---------------------------------------------------------------------------------------------------- CAUTION! A DIFFERENT value of the initialization vector ("Vector") should be used for each encryption with the same key ("Key"). Encrypting two messages with THE SAME key and THE SAME initialization vector drastically reduces security level! The key is a secret value. The initialization vector is not secret - it can be passed in plain form along with the encrypted message. -----------------------------------------------------------------------------------------------------------*) //--------------------------------------------------------------------------------------------------- //----------------------------------------- IMPLEMENTATION: ----------------------------------------- //--------------------------------------------------------------------------------------------------- //--- The "byte" type denotes an 8-bit unsigned integer //--- The "word" type denotes a 16-bit unsigned integer //--- The "longword" type denotes a 32-bit unsigned integer //----------- VMPC Stream Cipher variables: ----------- var P : array[0..255] of byte; s, n : byte; //----------- VMPC-MAC Authenticated Encryption Scheme variables: ----------- MAC : array[0..31] of byte; m1, m2, m3, m4, mn : byte; //----------------- Test data: ----------------- TestKey : array[0..15] of byte = ($96, $61, $41, $0A, $B7, $97, $D8, $A9, $EB, $76, $7C, $21, $17, $2D, $F6, $C7); TestVector : array[0..15] of byte = ($4B, $5C, $2F, $00, $3E, $67, $F3, $95, $57, $A8, $D2, $6F, $3D, $A2, $B1, $55); TestOutPInd : array[0..7] of byte = (0, 1, 2, 3, 252, 253, 254, 255); TestOutInd : array[0..15] of longword = (0,1,2,3,252,253,254,255,1020,1021,1022,1023,102396,102397,102398,102399); TestOutPBASIC : array[0..7] of byte = ($3F, $A5, $22, $67, $75, $B3, $D2, $C3); TestOutBASIC : array[0..15] of byte = ($A8, $24, $79, $F5, $B8, $FC, $66, $A4, $E0, $56, $40, $A5, $81, $CA, $49, $9A); //VMPCInitKeyBASIC_ASM(TestKey, TestVector, 16, 16); //P[TestOutPInd[x]]=TestOutPBASIC[x]; x=0,1,...,7 //Table[x]=0; x=0,1,...,102399 //VMPCEncrypt_ASM(Table, 102400); OR VMPCEncryptMAC_ASM(Table, 102400); //Table[TestOutInd[x]]=TestOutBASIC[x]; x=0,1,...,15 TestOutP : array[0..7] of byte = ($1F, $00, $E2, $03, $5C, $EE, $C2, $2B); TestOut : array[0..15] of byte = ($B6, $EB, $AE, $FE, $48, $17, $24, $73, $1D, $AE, $C3, $5A, $1D, $A7, $E1, $DC); //VMPCInitKey_ASM(TestKey, TestVector, 16, 16); //P[TestOutPInd[x]]=TestOutP[x]; x=0,1,...,7 //Table[x]=0; x=0,1,...,102399 //VMPCEncrypt_ASM(Table, 102400); OR VMPCEncryptMAC_ASM(Table, 102400); //Table[TestOutInd[x]]=TestOut[x]; x=0,1,...,15 TestOutMACBASIC : array[0..19] of byte = ($9B, $DA, $16, $E2, $AD, $0E, $28, $47, $74, $A3, $AC, $BC, $88, $35, $A8, $32, $6C, $11, $FA, $AD); //Table[x]=x; x=0,1,2,...,254,255 //VMPCInitKeyBASIC_ASM(TestKey, TestVector, 16, 16); //VMPCInitMAC_ASM; //VMPCEncryptMAC_ASM(Table, 256); //VMPCOutputMAC_ASM; //MAC[x]=TestOutMACBASIC[x]; x=0,1,...,19 TestOutMAC : array[0..19] of byte = ($A2, $B6, $0D, $B7, $B3, $90, $1D, $5C, $99, $61, $7C, $E2, $A3, $95, $02, $81, $75, $3A, $0C, $98); //Table[x]=x and 255; x=0,1,2,...,999998,999999; (Table[0]=0; Table[1]=1; ...; Table[999998]=62; Table[999999]=63) //VMPCInitKey_ASM(TestKey, TestVector, 16, 16); //VMPCInitMAC_ASM; //VMPCEncryptMAC_ASM(Table, 1000000); //VMPCOutputMAC_ASM; //MAC[x]=TestOutMAC[x]; x=0,1,...,19 //----------------------------------------------------------------------------------------------------------- const Permut123 : array[0..255] of byte = //Permut123[x]=x (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255); //----------------------------------------------------------------------------------------------------------- procedure VMPCInitKeyRound_ASM(var Data; Len, Src:longword); //[Data]=eax; Len=edx; Src=ecx //The procedure works only for Len=2,4,8,16,32,64 asm push edi push esi push ebp push ebx mov ebp, eax cmp ecx, 0 jnz @Start mov esi, offset Permut123 mov edi, offset P mov ecx, 64 cld rep movsd mov s, 0 @Start: mov eax, 768 //ah=3, al=0 mov al, s dec edx xor ebx, ebx @Step: mov esi, 0 @Loop: mov ebx, esi and ebx, edx //equivalent to "ebx modulo Len" for Len=2^X mov bl, [ebp+ebx] add bl, byte ptr [P+esi] add bl, al mov al, byte ptr [P+ebx] mov bl, al mov ch, byte ptr [P+ebx] mov cl, byte ptr [P+esi] mov byte ptr [P+ebx], cl mov byte ptr [P+esi], ch inc esi cmp esi, 256 jb @Loop dec ah jnz @Step mov s, al mov n, 0 pop ebx pop ebp pop esi pop edi end; procedure VMPCInitKey_ASM(var Key, Vec:array of byte; KeyLen, VecLen:byte); //KeyLen, VecLen = 2,4,8,16,32,64 begin VMPCInitKeyRound_ASM(Key, KeyLen, 0); VMPCInitKeyRound_ASM(Vec, VecLen, 1); VMPCInitKeyRound_ASM(Key, KeyLen, 1); end; procedure VMPCInitKeyBASIC_ASM(var Key, Vec:array of byte; KeyLen, VecLen:byte); //KeyLen, VecLen = 2,4,8,16,32,64 begin VMPCInitKeyRound_ASM(Key, KeyLen, 0); VMPCInitKeyRound_ASM(Vec, VecLen, 1); end; procedure VMPCInitMAC_ASM; asm push edi xor eax, eax mov edi, offset MAC mov ecx, 8 cld rep stosd mov m1, 0 mov m2, 0 mov m3, 0 mov m4, 0 mov mn, 0 pop edi end; procedure VMPCEncrypt_ASM(var Data; Len :longword); //[Data]=eax; Len=edx asm cmp edx, 0 jz @Finish; push edi push esi push ebp push ebx mov edi, eax mov ebp, edx add ebp, edi xor eax, eax xor ebx, ebx mov al, s mov bl, n mov esi, ebx @Loop: add al, byte ptr [P+esi] mov al, byte ptr [P+eax] mov bl, byte ptr [P+eax] mov bl, byte ptr [P+ebx] add bl, 1 mov bl, byte ptr [P+ebx] xor byte ptr [edi], bl mov bl, byte ptr [P+eax] mov cl, byte ptr [P+esi] mov byte ptr [P+eax], cl mov byte ptr [P+esi], bl inc esi and esi, 255 inc edi cmp edi, ebp jb @Loop mov s, al mov ebx, esi mov n, bl pop ebx pop ebp pop esi pop edi @Finish: end; procedure VMPCEncryptMAC_ASM(var Data; Len :longword); //[Data]=eax; Len=edx asm cmp edx, 0 jz @Finish; push edi push esi push ebp push ebx mov edi, eax mov ebp, edx add ebp, edi xor eax, eax xor ebx, ebx mov al, s mov bl, n mov esi, ebx mov cl, m1 mov ch, m2 mov dl, m3 mov dh, m4 @Loop: add al, byte ptr [P+esi] mov al, byte ptr [P+eax] mov bl, byte ptr [P+eax] mov bl, byte ptr [P+ebx] add bl, 1 mov ah, byte ptr [P+ebx] xor ah, byte ptr [edi] mov byte ptr [edi], ah mov bl, dh add bl, dl mov dh, byte ptr [P+ebx] mov bl, dl add bl, ch mov dl, byte ptr [P+ebx] mov bl, ch add bl, cl mov ch, byte ptr [P+ebx] mov bl, al add bl, ah add bl, cl mov cl, byte ptr [P+ebx] xor ah, ah mov ebx, esi and ebx, 7 xor word ptr[MAC+ebx*4], cx xor word ptr[MAC+ebx*4+2], dx mov bl, byte ptr [P+eax] mov bh, byte ptr [P+esi] mov byte ptr [P+eax], bh mov byte ptr [P+esi], bl xor ebx, ebx inc esi and esi, 255 inc edi cmp edi, ebp jb @Loop mov s, al mov ebx, esi mov n, bl mov m1, cl mov m2, ch mov m3, dl mov m4, dh pop ebx pop ebp pop esi pop edi @Finish: end; procedure VMPCDecryptMAC_ASM(var Data; Len :longword); //[Data]=eax; Len=edx asm cmp edx, 0 jz @Finish; push edi push esi push ebp push ebx mov edi, eax mov ebp, edx add ebp, edi xor eax, eax xor ebx, ebx mov al, s mov bl, n mov esi, ebx mov cl, m1 mov ch, m2 mov dl, m3 mov dh, m4 @Loop: add al, byte ptr [P+esi] mov al, byte ptr [P+eax] mov bl, byte ptr [P+eax] mov bl, byte ptr [P+ebx] add bl, 1 mov bl, byte ptr [P+ebx] mov ah, byte ptr [edi] xor bl, ah mov byte ptr [edi], bl mov bl, dh add bl, dl mov dh, byte ptr [P+ebx] mov bl, dl add bl, ch mov dl, byte ptr [P+ebx] mov bl, ch add bl, cl mov ch, byte ptr [P+ebx] mov bl, al add bl, ah add bl, cl mov cl, byte ptr [P+ebx] xor ah, ah mov ebx, esi and ebx, 7 xor word ptr[MAC+ebx*4], cx xor word ptr[MAC+ebx*4+2], dx mov bl, byte ptr [P+eax] mov bh, byte ptr [P+esi] mov byte ptr [P+eax], bh mov byte ptr [P+esi], bl xor ebx, ebx inc esi and esi, 255 inc edi cmp edi, ebp jb @Loop mov s, al mov ebx, esi mov n, bl mov m1, cl mov m2, ch mov m3, dl mov m4, dh pop ebx pop ebp pop esi pop edi @Finish: end; procedure VMPCOutputMAC_ASM_internal; asm push edi push esi push ebx mov edi, 1 xor eax, eax xor ebx, ebx mov al, s mov bl, n mov esi, ebx mov cl, m1 mov ch, m2 mov dl, m3 mov dh, m4 @Loop: add al, byte ptr [P+esi] mov al, byte ptr [P+eax] mov bl, dh add bl, dl add ebx, edi and ebx, 255 mov dh, byte ptr [P+ebx] mov bl, dl add bl, ch add ebx, edi and ebx, 255 mov dl, byte ptr [P+ebx] mov bl, ch add bl, cl add ebx, edi and ebx, 255 mov ch, byte ptr [P+ebx] mov bl, al add bl, cl add ebx, edi and ebx, 255 mov cl, byte ptr [P+ebx] mov ebx, esi and ebx, 7 xor word ptr[MAC+ebx*4], cx xor word ptr[MAC+ebx*4+2], dx mov bl, byte ptr [P+eax] mov bh, byte ptr [P+esi] mov byte ptr [P+eax], bh mov byte ptr [P+esi], bl xor ebx, ebx inc esi and esi, 255 inc edi cmp edi, 24 jbe @Loop mov s, al pop ebx pop esi pop edi end; procedure VMPCOutputMAC_ASM; begin VMPCOutputMAC_ASM_internal; VMPCInitKeyRound_ASM(MAC, 32, 1); FillChar(MAC, 20, 0); VMPCEncrypt_ASM(MAC, 20); end; procedure VMPCEraseKey_ASM; asm push edi xor eax, eax mov edi, offset P mov ecx, 64 cld rep stosd mov edi, offset MAC mov ecx, 8 rep stosd mov s, 0 mov n, 0 mov m1, 0 mov m2, 0 mov m3, 0 mov m4, 0 mov mn, 0 pop edi end; //--------------------------------------------------------------------------------------------------- //----------------------------------------------- END ----------------------------------------------- //---------------------------------------------------------------------------------------------------