(*--------------------------------------------------------------------------------------------------- Implementacja szyfru strumieniowego VMPC oraz schematu uwierzytelnionego szyfrowania VMPC-MAC w języku Pascal/Delphi Autor algorytmów: Bartosz Żółtak Autor implementacji: Bartosz Żółtak www.szyfrowanie.com ----------------------------------------------------------------------------------------------------- ----------------------- Wykorzystanie algorytmów: --------------------------------------------------- ----------------------------------------------------------------------------------------------------- var Klucz, Wektor : array[0..63] of byte; Wiadomosc : array[0..999] of byte; WiadomoscMAC : array[0..19] of byte; Szyfrowanie: VMPCInitKey(Klucz, Wektor, 16, 16); VMPCEncrypt(Wiadomosc, 1000); Deszyfrowanie: VMPCInitKey(Klucz, Wektor, 16, 16); VMPCEncrypt(Wiadomosc, 1000); (procedura VMPCEncrypt służy do szyfrowania i deszyfrowania). Szyfrowanie z uwierzytelnianiem (z kodem MAC): VMPCInitKey(Klucz, Wektor, 16, 16); VMPCInitMAC; VMPCEncryptMAC(Wiadomosc, 1000); VMPCOutputMAC; //Kod MAC umieszczony zostaje w 20-bajtowej tablicy "MAC" Move(MAC, WiadomoscMAC, 20); //Zapamietaj wygenerowany MAC w tablicy "WiadomoscMAC" Deszyfrowanie i weryfikacja kodu MAC: VMPCInitKey(Klucz, Wektor, 16, 16); VMPCInitMAC; VMPCDecryptMAC(Wiadomosc, 1000); VMPCOutputMAC; //Kod MAC umieszczony zostaje w 20-bajtowej tablicy "MAC" Jeśli 20-bajtowe tablice "MAC" i "WiadomoscMAC" są identyczne, wiadomość została poprawnie odszyfrowana - użyty został właściwy klucz i wiadomość nie została zmieniona. ---------------------------------------------------------------------------------------------------- Procedury VMPCInitKey / VMPCInitKey16 (wykorzystujące algorytm inicjowania klucza VMPC-KSA3) zapewniają wyższy poziom bezpieczeństwa, ale o około 1/3 niższą wydajność niż podstawowe procedury VMPCInitKeyBASIC / VMPCInitKey16BASIC. Jeśli tylko wydajność systemu pozwala, autor zaleca stosować procedury VMPCInitKey / VMPCInitKey16. Jednocześnie procedury VMPCInitKeyBASIC / VMPCInitKey16BASIC także pozostają bezpieczne. ---------------------------------------------------------------------------------------------------- UWAGA! Do każdego szyfrowania z tym samym kluczem ("Klucz") należy użyć INNEJ wartości wektora inicjującego "Wektor". Szyfrowanie dwóch wiadomości TYM SAMYM kluczem i TYM SAMYM wektorem inicjującym drastycznie obniża poziom bezpieczeństwa! Klucz jest wartością tajną. Wektor inicjujący jest wartością jawną - można go przekazać jawnie wraz z zaszyfrowaną wiadomością. ----------------------------------------------------------------------------------------------------*) //--------------------------------------------------------------------------------------------------- //----------------------------------------- IMPLEMENTACJA: ------------------------------------------ //--------------------------------------------------------------------------------------------------- //--- Typ danych "byte" oznacza zmienną 8-bitową bez znaku //--- Typ danych "word" oznacza zmienną 16-bitową bez znaku //--- Typ danych "longword" oznacza zmienną 32-bitową bez znaku //----------- Zmienne szyfru VMPC: ----------- var P : array[0..255] of byte; s, n : byte; //----------- Zmienne schematu uwierzytelnionego szyfrowania VMPC-MAC: ----------- MAC : array[0..31] of byte; m1, m2, m3, m4, mn : byte; //----------------- Dane testowe: ----------------- 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(TestKey, TestVector, 16, 16); LUB VMPCInitKey16BASIC(TestKey, TestVector); //P[TestOutPInd[x]]=TestOutPBASIC[x]; x=0,1,...,7 //Table[x]=0; x=0,1,...,102399 //VMPCEncrypt(Table, 102400); LUB VMPCEncryptMAC(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(TestKey, TestVector, 16, 16); LUB VMPCInitKey16(TestKey, TestVector); //P[TestOutPInd[x]]=TestOutP[x]; x=0,1,...,7 //Table[x]=0; x=0,1,...,102399 //VMPCEncrypt(Table, 102400); LUB VMPCEncryptMAC(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(TestKey, TestVector, 16, 16); LUB VMPCInitKey16BASIC(TestKey, TestVector); //VMPCInitMAC; //VMPCEncryptMAC(Table, 256); //VMPCOutputMAC; //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(TestKey, TestVector, 16, 16); LUB VMPCInitKey16(TestKey, TestVector); //VMPCInitMAC; //VMPCEncryptMAC(Table, 1000000); //VMPCOutputMAC; //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); //----------------------------------------------------------------------------------------------------------- //---------- Szyfr strumieniowy VMPC: ---------- procedure VMPCInitKeyRound(var Data:array of byte; Len, Src :byte); {Data: klucz lub wektor inicjujacy Len=1,2,3,...,64: dlugosc klucza/wektora inicjujacego (w bajtach) Src=0: pierwsze inicjowanie klucza (tablica P i zmienna s zostana najpierw przywrocone do stanu poczatkowego) Src=1: ponowne inicjowanie klucza, np. wektorem inicjujacym} var x : word; t,k : byte; begin if Src=0 then begin Move(Permut123, P, 256); s:=0; end; k:=0; n:=0; for x:=0 to 767 do begin s := P[ (s + P[n] + Data[k]) and 255 ]; t := P[n]; P[n] := P[s]; P[s] := t; inc(k); if k=Len then k:=0; n:=n+1; end; //for x end; procedure VMPCInitKeyRound16(var Data:array of byte; Src :byte); //Dla kluczy i wektorow o rozmiarze 16 bajtow (128 bitow) {Data: klucz lub wektor inicjujacy Src=0: pierwsze inicjowanie klucza (tablica P i zmienna s zostana najpierw przywrocone do stanu poczatkowego) Src=1: ponowne inicjowanie klucza, np. wektorem inicjujacym} var x : word; t,k : byte; begin if Src=0 then begin Move(Permut123, P, 256); s:=0; end; k:=0; n:=0; for x:=0 to 767 do begin s := P[ (s + P[n] + Data[k]) and 255 ]; t := P[n]; P[n] := P[s]; P[s] := t; k:=(k+1) and 15; n:=n+1; end; //for x end; procedure VMPCInitKey(var Key, Vec:array of byte; KeyLen, VecLen:byte); //KeyLen, VecLen = 1,2,3,...,64 begin VMPCInitKeyRound(Key, KeyLen, 0); VMPCInitKeyRound(Vec, VecLen, 1); VMPCInitKeyRound(Key, KeyLen, 1); end; procedure VMPCInitKey16(var Key, Vec:array of byte); //Dla kluczy i wektorow o rozmiarze 16 bajtow (128 bitow) begin VMPCInitKeyRound16(Key, 0); VMPCInitKeyRound16(Vec, 1); VMPCInitKeyRound16(Key, 1); end; procedure VMPCInitKeyBASIC(var Key, Vec:array of byte; KeyLen, VecLen:byte); //KeyLen, VecLen = 1,2,3,...,64 begin VMPCInitKeyRound(Key, KeyLen, 0); VMPCInitKeyRound(Vec, VecLen, 1); end; procedure VMPCInitKey16BASIC(var Key, Vec:array of byte); //Dla kluczy i wektorow o rozmiarze 16 bajtow (128 bitow) begin VMPCInitKeyRound16(Key, 0); VMPCInitKeyRound16(Vec, 1); end; procedure VMPCEncrypt(var Data:array of byte; Len:longword); var t:byte; x:longword; begin for x:=0 to Len-1 do begin s:=P[ (s+P[n]) and 255 ]; Data[x]:=Data[x] xor P[(P[P[ s ]]+1) and 255];; t := P[n]; P[n] := P[s]; P[s] := t; n:=n+1; end; //for x end; //---------- Schemat uwierzytelnionego szyfrowania VMPC-MAC: ---------- procedure VMPCInitMAC; begin m1:=0; m2:=0; m3:=0; m4:=0; mn:=0; Fillchar(MAC, 32, 0); end; procedure VMPCEncryptMAC(var Data:array of byte; Len:longword); var t:byte; x:longword; begin for x:=0 to Len-1 do begin s:=P[ (s+P[n]) and 255 ]; Data[x]:=Data[x] xor P[(P[P[ s ]]+1) and 255]; m4:=P[ (m4+m3) and 255 ]; m3:=P[ (m3+m2) and 255 ]; m2:=P[ (m2+m1) and 255 ]; m1:=P[ (m1 + s + Data[x]) and 255 ]; MAC[mn] := MAC[mn] xor m1; MAC[mn+1] := MAC[mn+1] xor m2; MAC[mn+2] := MAC[mn+2] xor m3; MAC[mn+3] := MAC[mn+3] xor m4; t := P[n]; P[n] := P[s]; P[s] := t; mn:=(mn+4) and 31; n:=n+1; end; //for x end; procedure VMPCDecryptMAC(var Data:array of byte; Len:longword); var t:byte; x:longword; begin for x:=0 to Len-1 do begin s:=P[ (s+P[n]) and 255 ]; m4:=P[ (m4+m3) and 255 ]; m3:=P[ (m3+m2) and 255 ]; m2:=P[ (m2+m1) and 255 ]; m1:=P[ (m1 + s + Data[x]) and 255 ]; MAC[mn] := MAC[mn] xor m1; MAC[mn+1] := MAC[mn+1] xor m2; MAC[mn+2] := MAC[mn+2] xor m3; MAC[mn+3] := MAC[mn+3] xor m4; Data[x]:=Data[x] xor P[(P[P[ s ]]+1) and 255]; t := P[n]; P[n] := P[s]; P[s] := t; mn:=(mn+4) and 31; n:=n+1; end; //for x end; procedure VMPCOutputMAC; var t:byte; x:longword; begin for x:=1 to 24 do begin s:=P[ (s+P[n]) and 255 ]; m4:=P[ (m4 + m3 + x) and 255 ]; m3:=P[ (m3 + m2 + x) and 255 ]; m2:=P[ (m2 + m1 + x) and 255 ]; m1:=P[ (m1 + s + x) and 255 ]; MAC[mn] := MAC[mn] xor m1; MAC[mn+1] := MAC[mn+1] xor m2; MAC[mn+2] := MAC[mn+2] xor m3; MAC[mn+3] := MAC[mn+3] xor m4; t := P[n]; P[n] := P[s]; P[s] := t; mn:=(mn+4) and 31; n:=n+1; end; //for x VMPCInitKeyRound(MAC, 32, 1); FillChar(MAC, 20, 0); VMPCEncrypt(MAC, 20); end; procedure VMPCEraseKey; begin FillChar(P, sizeof(P), 0); FillChar(MAC, sizeof(MAC), 0); s:=0; n:=0; m1:=0; m2:=0; m3:=0; m4:=0; mn:=0; end; //--------------------------------------------------------------------------------------------------- //--------------------------------------------- KONIEC ---------------------------------------------- //---------------------------------------------------------------------------------------------------