(*--------------------------------------------------------------------------------------------------- Implementation of the Cryptographically Secure Pseudo-Random Number Generator VMPC-R in Pascal/Delphi Author of the algorithms: Bartosz Zoltak Author of the implementation: Bartosz Zoltak www.vmpcfunction.com ----------------------------------------------------------------------------------------------------- ----------------------- Usage of the algorithm: ----------------------------------------------------- ----------------------------------------------------------------------------------------------------- var Key, Vector : array[0..255] of byte; Message : array[0..999] of byte; Pseudo-Random Number Generation / Encryption: VMPCRInitKey(Key, Vector, 32, 32); VMPCREncrypt(Message, 1000); Decryption: VMPCRInitKey(Key, Vector, 32, 32); VMPCREncrypt(Message, 1000); (the VMPRCEncrypt procedure is used for pseudo-random number generation, encryption and decryption). The (**) sign marks the code which decides whether the algorithm works in the pseudo-random number generation or encryption/decryption mode. ---------------------------------------------------------------------------------------------------- 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 "longword" type denotes a 32-bit unsigned integer //----------- VMPC-R variables: ----------- var P, S : array[0..255] of byte; a, b, c, d, e, f, n : byte; //----------------- Test data: ----------------- TestOutPSInd : array[0..7] of byte = (0, 1, 2, 3, 252, 253, 254, 255); TestOutInd : array[0..15] of longword = (0,1,2,3,254,255,256,257,1000, 1001, 10000, 10001, 100000, 100001, 1000000, 1000001); TestKey : array[0..8] of byte = (11, 22, 33, 144, 155, 166, 233, 244, 255); TestVector : array[0..7] of byte = (255, 250, 200, 150, 100, 50, 5, 1); TestKey32 : array[0..31] of byte = (104, 9, 46, 231, 132, 149, 234, 147, 224, 97, 230, 127, 124, 109, 34, 171, 88, 185, 158, 23, 116, 69, 90, 195, 208, 17, 86, 175, 108, 29, 146, 219); //RND=123; repeat 32 times:{RND:=RND*134775813+1; output=(RND and 255)} TestVector32 : array[0..31] of byte = (149, 234, 147, 224, 97, 230, 127, 124, 109, 34, 171, 88, 185, 158, 23, 116, 69, 90, 195, 208, 17, 86, 175, 108, 29, 146, 219, 72, 105, 14, 71, 100); //RND=132; repeat 32 times:{RND:=RND*134775813+1; output=(RND and 255)} TestKey256 : array[0..255] of byte = (147, 224, 97, 230, 127, 124, 109, 34, 171, 88, 185, 158, 23, 116, 69, 90, 195, 208, 17, 86, 175, 108, 29, 146, 219, 72, 105, 14, 71, 100, 245, 202, 243, 192, 193, 198, 223, 92, 205, 2, 11, 56, 25, 126, 119, 84, 165, 58, 35, 176, 113, 54, 15, 76, 125, 114, 59, 40, 201, 238, 167, 68, 85, 170, 83, 160, 33, 166, 63, 60, 45, 226, 107, 24, 121, 94, 215, 52, 5, 26, 131, 144, 209, 22, 111, 44, 221, 82, 155, 8, 41, 206, 7, 36, 181, 138, 179, 128, 129, 134, 159, 28, 141, 194, 203, 248, 217, 62, 55, 20, 101, 250, 227, 112, 49, 246, 207, 12, 61, 50, 251, 232, 137, 174, 103, 4, 21, 106, 19, 96, 225, 102, 255, 252, 237, 162, 43, 216, 57, 30, 151, 244, 197, 218, 67, 80, 145, 214, 47, 236, 157, 18, 91, 200, 233, 142, 199, 228, 117, 74, 115, 64, 65, 70, 95, 220, 77, 130, 139, 184, 153, 254, 247, 212, 37, 186, 163, 48, 241, 182, 143, 204, 253, 242, 187, 168, 73, 110, 39, 196, 213, 42, 211, 32, 161, 38, 191, 188, 173, 98, 235, 152, 249, 222, 87, 180, 133, 154, 3, 16, 81, 150, 239, 172, 93, 210, 27, 136, 169, 78, 135, 164, 53, 10, 51, 0, 1, 6, 31, 156, 13, 66, 75, 120, 89, 190, 183, 148, 229, 122, 99, 240, 177, 118, 79, 140, 189, 178, 123, 104, 9, 46, 231, 132, 149, 234); //RND=234; repeat 256 times:{RND:=RND*134775813+1; output=(RND and 255)} TestOutP : array[0..7] of byte = (97,218,106,125,139,86,36,126); TestOutS : array[0..7] of byte = (152,143,19,154,92,25,24,157); TestOut : array[0..15] of byte = (49, 161, 79, 69, 85, 237, 96, 243, 181, 184, 136, 99, 67, 27, 253, 231); //VMPCRInitKey(TestKey, TestVector, 9, 8); //P[TestOutPSInd[x]]=TestOutP[x]; x=0,1,...,7 //S[TestOutPSInd[x]]=TestOutS[x]; x=0,1,...,7 //VMPCREncrypt(Table, 1000002); //Table[TestOutInd[x]]=TestOut[x]; x=0,1,...,15 TestOutP32 : array[0..7] of byte = (76, 44, 167, 7, 250, 147, 240, 51); TestOutS32 : array[0..7] of byte = (239, 59, 110, 207, 98, 23, 178, 227); TestOut32 : array[0..15] of byte = (219, 178, 157, 119, 2, 155, 62, 20, 3, 239, 236, 81, 195, 11, 186, 127); //VMPCRInitKey(TestKey32, TestVector32, 32, 32); OR VMPCRInitKey32(TestKey32, TestVector32); //P[TestOutPSInd[x]]=TestOutP32[x]; x=0,1,...,7 //S[TestOutPSInd[x]]=TestOutS32[x]; x=0,1,...,7 //VMPCREncrypt(Table, 1000002); //Table[TestOutInd[x]]=TestOut32[x]; x=0,1,...,15 TestOutP256 : array[0..7] of byte = (10, 34, 13, 239, 209, 9, 154, 220); TestOutS256 : array[0..7] of byte = (253, 106, 200, 178, 75, 251, 129, 209); TestOut256 : array[0..15] of byte = (201, 85, 155, 17, 187, 48, 55, 198, 110, 179, 189, 210, 4, 15, 253, 83); //VMPCRInitKey(TestKey256, TestVector, 256, 8); //P[TestOutPSInd[x]]=TestOutP256[x]; x=0,1,...,7 //S[TestOutPSInd[x]]=TestOutS256[x]; x=0,1,...,7 //VMPCREncrypt(Table, 1000002); //Table[TestOutInd[x]]=TestOut256[x]; x=0,1,...,15 //------------------------------------------------------------------------------------------------------------- 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); InitKeyRounds : array[0..255] of byte = //InitKeyRounds[x]=Ceiling((x+1)*(x+1) / (6*256)) (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, 43, 43, 43); //------------------------------------------------------------------------------------ procedure VMPCRInitKeyRound(var Data:array of byte; Len: longword); //Data: key or initialization vector //Len=1,2,3,...,256: key/initialization vector length (in bytes) var x,t,i,r: byte; begin i:=0; for r:=1 to InitKeyRounds[Len-1] do begin //InitDataRounds[Len-1] = Ceiling(Len*Len / (6*256)) for x:=0 to 255 do begin //x will take on the same values as n in the algorithm's specification a:=(P[(a+f+Data[i]) and 255]+i) and 255; i:=i+1; if i=Len then i:=0; b:=(S[(b+a+Data[i]) and 255]+i) and 255; i:=i+1; if i=Len then i:=0; c:=(P[(c+b+Data[i]) and 255]+i) and 255; i:=i+1; if i=Len then i:=0; d:=(S[(d+c+Data[i]) and 255]+i) and 255; i:=i+1; if i=Len then i:=0; e:=(P[(e+d+Data[i]) and 255]+i) and 255; i:=i+1; if i=Len then i:=0; f:=(S[(f+e+Data[i]) and 255]+i) and 255; i:=i+1; if i=Len then i:=0; t:=P[x]; P[x]:=P[b]; P[b]:=t; t:=S[x]; S[x]:=S[e]; S[e]:=t; t:=P[d]; P[d]:=P[f]; P[f]:=t; t:=S[a]; S[a]:=S[c]; S[c]:=t; end; //for x end; //for r end; procedure VMPCRInitKeyRound32(var Data:array of byte); //For 32-byte (256-bit) keys and vectors //Data: key or initialization vector var x,t,i,r: byte; begin i:=0; for r:=1 to InitKeyRounds[31] do begin //InitKeyRounds[31] = Ceiling(32*32 / (6*256)) for x:=0 to 255 do begin //x will take on the same values as n in the algorithm's specification a:=(P[(a+f+Data[i]) and 255]+i) and 255; i:=(i+1) and 31; b:=(S[(b+a+Data[i]) and 255]+i) and 255; i:=(i+1) and 31; c:=(P[(c+b+Data[i]) and 255]+i) and 255; i:=(i+1) and 31; d:=(S[(d+c+Data[i]) and 255]+i) and 255; i:=(i+1) and 31; e:=(P[(e+d+Data[i]) and 255]+i) and 255; i:=(i+1) and 31; f:=(S[(f+e+Data[i]) and 255]+i) and 255; i:=(i+1) and 31; t:=P[x]; P[x]:=P[b]; P[b]:=t; t:=S[x]; S[x]:=S[e]; S[e]:=t; t:=P[d]; P[d]:=P[f]; P[f]:=t; t:=S[a]; S[a]:=S[c]; S[c]:=t; end; //for x end; //for r end; procedure VMPCRInitKeyFinalize; var x,t: byte; begin for x:=0 to 255 do begin a:=P[(a+c+S[n]) and 255]; b:=P[(b+a) and 255]; c:=P[(c+b) and 255]; d:=S[(d+f+P[n]) and 255]; e:=S[(e+d) and 255]; f:=S[(f+e) and 255]; t:=P[n]; P[n]:=P[f]; P[f]:=t; t:=S[n]; S[n]:=S[a]; S[a]:=t; n:=(n+1) and 255; end; //for x end; procedure VMPCRInitKey(var Key,Vec:array of byte; KeyLen,VecLen :longword); //LeyLen, VecLen={1,2,3,...,256} var x:byte; begin Move(Permut123, P, 256); Move(Permut123, S, 256); a:=0; b:=0; c:=0; d:=0; e:=0; f:=0; n:=0; VMPCRInitKeyRound(Key, KeyLen); VMPCRInitKeyRound(Vec, VecLen); VMPCRInitKeyRound(Key, KeyLen); n:=S[(S[S[(c+d) and 255]]+1) and 255]; VMPCRInitKeyFinalize; end; procedure VMPCRInitKey32(var Key,Vec:array of byte); //For 32-byte (256-bit) keys and vectors var x:byte; begin Move(Permut123, P, 256); Move(Permut123, S, 256); a:=0; b:=0; c:=0; d:=0; e:=0; f:=0; n:=0; VMPCRInitKeyRound32(Key); VMPCRInitKeyRound32(Vec); VMPCRInitKeyRound32(Key); n:=S[(S[S[(c+d) and 255]]+1) and 255]; VMPCRInitKeyFinalize; end; procedure VMPCREncrypt(var Data:array of byte; Len:longword); var x: longword; t: byte; begin for x:=0 to Len-1 do begin a:=P[(a+c+S[n]) and 255]; b:=P[(b+a) and 255]; c:=P[(c+b) and 255]; d:=S[(d+f+P[n]) and 255]; e:=S[(e+d) and 255]; f:=S[(f+e) and 255]; Data[x]:=S[(S[S[(c+d) and 255]]+1) and 255]; //pseudo-random number generation (**) //Data[x]:=Data[x] xor S[(S[S[(c+d) and 255]]+1) and 255]; //encryption / decryption (**) t:=P[n]; P[n]:=P[f]; P[f]:=t; t:=S[n]; S[n]:=S[a]; S[a]:=t; n:=(n+1) and 255; end; //for x end; procedure VMPCREraseKey; begin FillChar(P, sizeof(P), 0); FillChar(S, sizeof(S), 0); a:=0; b:=0; c:=0; d:=0; e:=0; f:=0; n:=0; end; //--------------------------------------------------------------------------------------------------- //----------------------------------------------- END ----------------------------------------------- //---------------------------------------------------------------------------------------------------