/*--------------------------------------------------------------------------------------------------- Implementation of the Cryptographically Secure Pseudo-Random Number Generator VMPC-R in C Author of the algorithms: Bartosz Zoltak Author of the implementation: Bartosz Zoltak www.vmpcfunction.com ----------------------------------------------------------------------------------------------------- ----------------------- Usage of the algorithm: ----------------------------------------------------- ----------------------------------------------------------------------------------------------------- unsigned char Key[256], Vector[256]; Message[1000]; Pseudo-Random Number Generation / Encryption: VMPCRInitKey(Key, Vector, 32, 32); VMPCREncrypt(Message, 1000); Decryption: VMPCRInitKey(Key, Vector, 16, 16); VMPCREncrypt(Message, 1000); (the VMPRCEncrypt function 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 "int" type denotes a 32-bit integer //----------- VMPC-R variables: ----------- unsigned char P[256], S[256]; unsigned char a, b, c, d, e, f, n; //----------------- Test data: ----------------- unsigned char TestOutPSInd[8] = {0, 1, 2, 3, 252, 253, 254, 255}; unsigned int TestOutInd[16] = {0, 1, 2, 3, 254, 255, 256, 257,1000,1001,10000,10001,100000,100001,1000000,1000001}; unsigned char TestKey[9] = {11,22,33,144,155,166,233,244,255}; unsigned char TestVector[8] = {255,250,200,150,100,50,5,1}; unsigned char TestKey32[32] = {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 & 255)} unsigned char TestVector32[32] = {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 & 255)} unsigned char TestKey256[256] = {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 & 255)} unsigned char TestOutP[8] = {97,218,106,125,139,86,36,126}; unsigned char TestOutS[8] = {152,143,19,154,92,25,24,157}; unsigned char TestOut[16] = {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 unsigned char TestOutP32[8] = {76, 44, 167, 7, 250, 147, 240, 51}; unsigned char TestOutS32[8] = {239, 59, 110, 207, 98, 23, 178, 227}; unsigned char TestOut32[16] = {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 unsigned char TestOutP256[8] = {10, 34, 13, 239, 209, 9, 154, 220}; unsigned char TestOutS256[8] = {253, 106, 200, 178, 75, 251, 129, 209}; unsigned char TestOut256[16] = {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 //------------------------------------------------------------------------------------------------------------- unsigned char Permut123[256]= //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}; unsigned char InitKeyRounds[256]= //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}; //------------------------------------------------------------------------------------------------------------- void VMPCRInitKeyRound(unsigned char Data[], int Len) //Data: key or initialization vector //Len=1,2,3,...,256: key/initialization vector length (in bytes) { unsigned char i, t; i=0; for (int r=1; r<=InitKeyRounds[Len-1]; r++) { //InitKeyRounds[Len-1] = Ceiling(Len*Len / (6*256)) for (int x=0; x<256; x++) { //x will take on the same values as n in the algorithm's specification a=(P[ (a + f + Data[i]) & 255 ] + i) & 255; i++; if (i==Len) i=0; b=(S[ (b + a + Data[i]) & 255 ] + i) & 255; i++; if (i==Len) i=0; c=(P[ (c + b + Data[i]) & 255 ] + i) & 255; i++; if (i==Len) i=0; d=(S[ (d + c + Data[i]) & 255 ] + i) & 255; i++; if (i==Len) i=0; e=(P[ (e + d + Data[i]) & 255 ] + i) & 255; i++; if (i==Len) i=0; f=(S[ (f + e + Data[i]) & 255 ] + i) & 255; i++; if (i==Len) 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; } } } void VMPCRInitKeyRound32(unsigned char Data[]) //For 32-byte (256-bit) keys and vectors //Data: key or initialization vector { unsigned char i, t; i=0; for (int r=1; r<=InitKeyRounds[31]; r++) { //InitKeyRounds[31] = Ceiling(32*32 / (6*256)) for (int x=0; x<256; x++) { //x will take on the same values as n in the algorithm's specification a=(P[ (a + f + Data[i]) & 255 ] + i) & 255; i=++i & 31; b=(S[ (b + a + Data[i]) & 255 ] + i) & 255; i=++i & 31; c=(P[ (c + b + Data[i]) & 255 ] + i) & 255; i=++i & 31; d=(S[ (d + c + Data[i]) & 255 ] + i) & 255; i=++i & 31; e=(P[ (e + d + Data[i]) & 255 ] + i) & 255; i=++i & 31; f=(S[ (f + e + Data[i]) & 255 ] + i) & 255; i=++i & 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; } } } void VMPCRInitKeyFinalize() { unsigned char t; for (unsigned int x=0; x<256; x++) { a=P[ (a + c + S[n]) & 255 ]; b=P[ (b + a) & 255 ]; c=P[ (c + b) & 255 ]; d=S[ (d + f + P[n]) & 255 ]; e=S[ (e + d) & 255 ]; f=S[ (f + e) & 255 ]; t=P[n]; P[n]=P[f]; P[f]=t; t=S[n]; S[n]=S[a]; S[a]=t; n++; } } void VMPCRInitKey(unsigned char Key[], unsigned char Vec[], int KeyLen, int VecLen) //LeyLen, VecLen={1,2,3,...,256} { memcpy(P, Permut123, 256); memcpy(S, Permut123, 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) & 255 ]]+1) & 255]; VMPCRInitKeyFinalize(); } void VMPCRInitKey32(unsigned char Key[], unsigned char Vec[]) //For 32-byte (256-bit) keys and vectors { memcpy(P, Permut123, 256); memcpy(S, Permut123, 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) & 255 ]]+1) & 255]; VMPCRInitKeyFinalize(); } void VMPCREncrypt(unsigned char Data[], unsigned int Len) { unsigned char t; for (unsigned int x=0; x