伪随机数发生器为同一种子产生不同的序列

时间:2016-09-12 01:48:51

标签: c++ random cryptography

我正在制作一个加密算法(只是为了好玩),这取决于我用密钥播种的伪随机数生成器。 PRNG应该为相同的种子(初始化密钥)产生相同的序列,但是当我在encryptdecrypt方法中声明它们并调用它们时,这种情况就不会发生。

代码:

crypto.hpp:

#ifndef CRYPTO_HPP
#define CRYPTO_HPP

#include <cstdlib>
#include <cstdint>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include "quadrant.hpp"

static const uint8_t sbox1[256] = {
    0x68,0x81,0x90,0xf4,0x2f,0x47,0xdc,0xb1,0xe2,0xff,0xe3,0x88,0xeb,0xcb,0xba,0x9c,
    0xc0,0x0a,0xd4,0x78,0x2c,0xc6,0x5c,0x33,0xea,0x8f,0x15,0x22,0x38,0xf1,0xbe,0xc4,
    0x82,0x30,0xb6,0xa4,0x8c,0x11,0xe6,0xe5,0x13,0x1d,0xa0,0x67,0x75,0x06,0x8d,0xf7,
    0x54,0x3f,0x48,0x4f,0x66,0x16,0x07,0x28,0xbc,0x91,0xb9,0xe7,0x0d,0xb3,0xa6,0x7f,
    0x2a,0x2d,0xe4,0xb7,0x98,0x1f,0x5b,0x87,0x1e,0xc9,0x6d,0x51,0x3a,0x99,0x04,0xee,
    0x03,0xac,0xfa,0x52,0x57,0x29,0x21,0x2e,0xbf,0x94,0xcc,0xcd,0x92,0xb5,0xc7,0x9e,
    0xc5,0xbb,0xd7,0xd8,0x60,0xed,0x20,0x26,0xb8,0x45,0x6a,0x01,0x34,0xa9,0x69,0xc1,
    0xda,0xf5,0xfe,0x23,0x5f,0x70,0x9a,0x95,0x1c,0xd9,0xa3,0x8a,0x61,0xce,0x79,0x93,
    0xd5,0x9b,0x4d,0xf0,0xc2,0x10,0x14,0x1b,0x18,0x0e,0xef,0xfd,0x71,0xab,0x12,0x9f,
    0x44,0xf2,0x3b,0xaa,0xca,0x59,0x3c,0x0f,0x37,0x0b,0x85,0xdf,0xfc,0x2b,0x43,0x6c,
    0x42,0x00,0x89,0x53,0xae,0xd6,0x3d,0x02,0xe9,0x7c,0x62,0xe0,0x8b,0xb2,0x5a,0x7a,
    0x6e,0xd0,0x6f,0xec,0xde,0x5d,0x4b,0x84,0x31,0x0c,0x3e,0x7d,0x8e,0x96,0x27,0xcf,
    0x74,0xaf,0x58,0xa1,0xa8,0x65,0x72,0x9d,0x09,0x73,0x49,0x6b,0xa7,0xe1,0xe8,0xf8,
    0x80,0xf3,0x97,0xf9,0x4e,0x86,0x55,0x63,0xd2,0xdd,0x25,0x50,0x83,0xc8,0x05,0x08,
    0x7b,0xa5,0x4a,0x76,0x64,0x5e,0x35,0x1a,0xad,0x17,0xf6,0xc3,0xdb,0xb4,0xfb,0x7e,
    0x39,0x24,0xd3,0x32,0x36,0xa2,0x19,0x46,0x56,0x77,0xd1,0x40,0x4c,0x41,0xbd,0xb0
};

static const uint8_t sbox2[256] = {
    0x9f,0x33,0x84,0x4d,0xd8,0x04,0xdf,0x5e,0xd5,0xb0,0x55,0x82,0x26,0x57,0x2d,0x0d,
    0x19,0x36,0xdc,0xbd,0x5c,0xe9,0x4f,0x45,0xac,0xf0,0xca,0x25,0xc4,0x93,0xee,0xf9,
    0x68,0x34,0x0e,0x11,0x5d,0x00,0x2b,0xaa,0xa7,0xcb,0xb7,0x3d,0x32,0xc9,0xbe,0x0a,
    0x47,0xea,0x70,0xe2,0x88,0x46,0x10,0xd2,0xfd,0xd3,0x49,0x38,0x83,0x5b,0xb2,0xdb,
    0x22,0xef,0x7d,0xfa,0x9c,0xda,0x4b,0x9a,0xb5,0x2f,0xc6,0xf4,0x9d,0xc8,0x92,0x1c,
    0xd0,0xbf,0x7b,0xfb,0x64,0x97,0x90,0x24,0xb4,0x52,0x73,0xa2,0x6f,0x80,0x61,0x23,
    0x99,0x59,0xad,0x35,0x63,0x1d,0x06,0xe7,0x3a,0x30,0x27,0x89,0x91,0x7e,0xab,0xb3,
    0xb9,0xa8,0x71,0x72,0xfe,0xdd,0xd4,0x14,0xc5,0x6b,0xf3,0x4c,0x3c,0x5f,0xa5,0x74,
    0x8f,0x21,0x41,0x50,0x0b,0x1e,0x43,0x18,0x62,0xe0,0xcf,0x12,0xd7,0x8e,0xde,0x03,
    0xbc,0xe1,0x6d,0x1a,0xfc,0xd6,0x66,0xc1,0x15,0x9b,0xb8,0x29,0xbb,0xc3,0x0f,0x08,
    0x9e,0x81,0x96,0x4a,0x16,0x94,0xe5,0x75,0x86,0x60,0x67,0xf7,0x44,0x7c,0x77,0x05,
    0xff,0x95,0xf1,0xc0,0x02,0x7f,0xe6,0xa9,0xaf,0x5a,0x01,0xc2,0xe8,0x39,0x58,0x85,
    0xec,0xcc,0x07,0x53,0xa4,0x28,0xf8,0xba,0x4e,0x98,0x79,0x17,0xd9,0x1f,0x40,0xa0,
    0xf5,0x20,0xe3,0x2e,0xeb,0x56,0xa1,0x7a,0x31,0x8b,0x8d,0xd1,0x2c,0x8c,0x42,0x0c,
    0x87,0xa3,0x78,0x6e,0xf2,0xcd,0x8a,0x3f,0xce,0xae,0x09,0xf6,0xb6,0x6a,0xc7,0x51,
    0x48,0x6c,0x65,0x1b,0x76,0x3e,0xa6,0x3b,0x37,0x54,0x2a,0x13,0xe4,0x69,0xed,0xb1
};

static const uint8_t sbox3[256] = {
    0x34,0x8c,0x07,0x0d,0xda,0xf8,0xa6,0x13,0xd6,0xf5,0xb2,0x58,0xc6,0x04,0xe3,0x3f,
    0xf1,0x8a,0x15,0x69,0xa9,0x50,0x82,0x91,0x1b,0x27,0xed,0x32,0x99,0xd0,0x73,0x5a,
    0xc3,0xbe,0xbf,0xc0,0x40,0x1f,0xf9,0xd5,0xb4,0x66,0x9e,0x02,0xce,0xb0,0xb9,0x20,
    0xe8,0x68,0x01,0xa0,0xe6,0x7d,0x19,0xd7,0x35,0x62,0x74,0x7e,0x3c,0xa2,0x71,0x3d,
    0xbc,0x08,0xb8,0x2a,0x81,0xbd,0x12,0x83,0xb1,0x98,0x41,0x88,0x00,0x06,0xb6,0x64,
    0xbb,0x9d,0x87,0x1a,0x6e,0x2c,0x3a,0x4b,0x96,0x14,0x29,0xe1,0xa8,0xf2,0x6b,0x5e,
    0x53,0xdf,0x23,0x51,0xcf,0x9c,0xab,0xf7,0xf6,0xfe,0x4c,0x78,0x6c,0xcc,0x4a,0x57,
    0x09,0x8e,0x67,0x33,0xd2,0x6a,0xaf,0x80,0x8f,0xa3,0x0e,0x86,0x4f,0xea,0xc8,0xba,
    0x45,0x95,0xe7,0x49,0x94,0xe2,0xd8,0x3b,0xcb,0x05,0x9f,0xdc,0x2f,0x26,0xf4,0x2d,
    0xe5,0x61,0x6d,0x56,0x38,0x22,0x60,0x72,0x8d,0xf3,0x37,0x63,0xeb,0x7f,0x46,0xaa,
    0x5c,0x4e,0xd4,0x7b,0xfd,0x76,0xec,0x11,0x28,0x5f,0x21,0x2e,0xe0,0x16,0x4d,0x0f,
    0x77,0xef,0x52,0x2b,0xb5,0x39,0xca,0x93,0x84,0x3e,0x7c,0x6f,0xfc,0xf0,0x75,0x55,
    0xd1,0xc1,0xee,0x9b,0xa1,0xb3,0xff,0x5d,0x42,0x79,0xa5,0x70,0x44,0xd3,0x31,0x90,
    0x25,0x5b,0xc9,0x7a,0x65,0x10,0xa4,0x47,0xac,0x30,0x17,0x0a,0x8b,0xdd,0xe9,0x0b,
    0x9a,0xc7,0xc4,0xde,0x89,0x92,0xdb,0xb7,0xad,0x18,0x43,0xfa,0x0c,0x1c,0x1d,0x24,
    0xfb,0xcd,0xd9,0x48,0x54,0xc2,0xae,0x97,0x1e,0x03,0xa7,0x36,0xc5,0x59,0x85,0xe4
};

class cipher
{
    private:
    // Initialize key
    static void key_sched(const char* key,uint32_t ks,uint32_t s_k[16]) // Key length: 256 bits = 32 bytes
    {
        uint32_t i, j;
        int ix, iy;
        uint8_t tk[2*ks];
        uint32_t s_aux[16];
        uint32_t mask[16] = { // Based on decimal part of Phi
            0x3779b97f,0x4a7c15f3,0x9cc0605c,0xedc83410,
            0x82276bf3,0xa27251f8,0x6c6a11d0,0xc18e9527,
            0x67f0b153,0xd27b7f03,0x47045b5b,0xf1827f01,
            0x886f0928,0x403002c1,0xd64ba40f,0x335e36f0
        };

        for (i=0;i<16;i++)
            s_aux[i] = 0x0;

        for (i=0;i<ks;i++)
        {
            tk[2*i  ] = sbox1[key[i]];
            tk[2*i+1] = sbox2[key[i]];
        }

        for (i=0;i<2*ks;i++)
        {
            ix = i%4; iy = i/4;
            s_aux[iy] |= uint32_t(tk[i]) << (8*(3-ix));
        }

        uint32_t tmp;
        for (i=0;i<16;i++)
        {
            s_k[i] = (s_aux[i] << 13) | (s_aux[(i+1)%16] >> 18);
            s_k[i] ^= mask[i];
            tmp = s_k[i];
            s_k[i] = ((uint32_t)sbox3[(tmp>>24)&0xff] << 24) |
                     ((uint32_t)sbox3[(tmp>>16)&0xff] << 16) |
                     ((uint32_t)sbox3[(tmp>> 8)&0xff] <<  8) |
                     ((uint32_t)sbox3[(tmp>> 0)&0xff] <<  0);
        }
    }
    public:

    // Encrypt
    static void encrypt(const char* data,uint32_t ds,uint8_t* out,const char* key,uint32_t ks)
    {
        std::cout << "Key used: " << key << "\n";
        uint32_t seed_k[16];
        key_sched(key,ks,seed_k);

        // PRNG seeded by key
        quadrant krng(seed_k[ 0],seed_k[ 1],seed_k[ 2],seed_k[ 3],seed_k[ 4],seed_k[ 5],seed_k[ 6],seed_k[ 7],
                      seed_k[ 8],seed_k[ 9],seed_k[10],seed_k[11],seed_k[12],seed_k[13],seed_k[14],seed_k[15]);
        std::cout << "[encrypt] Test krng(): " << krng() << "\n";

        // do encryption...
    }

    // Decrypt
    static void decrypt(uint8_t* data,uint32_t ds,uint8_t* out,const char* key,uint32_t ks)
    {
        std::cout << "Key used: " << key << "\n";
        uint32_t seed_k[16];
        key_sched(key,ks,seed_k);

        // PRNG seeded by key
        quadrant krng(seed_k[ 0],seed_k[ 1],seed_k[ 2],seed_k[ 3],seed_k[ 4],seed_k[ 5],seed_k[ 6],seed_k[ 7],
                      seed_k[ 8],seed_k[ 9],seed_k[10],seed_k[11],seed_k[12],seed_k[13],seed_k[14],seed_k[15]);
        std::cout << "[decrypt] Test krng(): " << krng() << "\n";

        // do decryption...
    }
};

#endif

ctest.cpp:

#include <iostream>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <string>
#include "crypto.hpp"

using namespace std;

int main()
{
    string ptx = "Plaintext";
    string key = "Key";
    uint8_t* encr;
    uint8_t* decr;
    uint32_t esiz = 0;

    cipher::encrypt(
        ptx.c_str(),ptx.length(),
        encr,esiz,
        key.c_str(),key.length()
    );
    cipher::decrypt(encr,esiz,decr,key.c_str(),key.length());
}

我做的PRNG(quadrant.hpp)是here

此外,这是它的输出(返回的krng()值不相同):

Key used: Key
[encrypt] Test krng(): 2213112449
Key used: Key
[decrypt] Test krng(): 2237675595

如何解决这个问题?

编辑:现在我在cipher课程之外初始化PRNG,并将其播种到方法中。因此,即使在多次运行期间,它也能正确地为方法生成相同的序列。也就是说,我解决了它。

增强代码:

static quadrant krng;

class cipher
{
    private:
    static void key_sched(const char* key,uint32_t ks,uint32_t s_k[16])
    {
        // the same function as above
    }
    public:

    static void encrypt(const char* data,uint32_t ds,uint8_t* out,const char* key,uint32_t ks)
    {
        uint32_t seed_k[16];
        key_sched(key,ks,seed_k);

        krng.seed(
            seed_k[ 0],seed_k[ 1],seed_k[ 2],seed_k[ 3],
            seed_k[ 4],seed_k[ 5],seed_k[ 6],seed_k[ 7],
            seed_k[ 8],seed_k[ 9],seed_k[10],seed_k[11],
            seed_k[12],seed_k[13],seed_k[14],seed_k[15]
        );
        std::cout << "[encrypt] Test krng(): " << krng() << "\n";

        // do encryption...
    }

    static void decrypt(uint8_t* data,uint32_t ds,uint8_t* out,const char* key,uint32_t ks)
    {
        uint32_t seed_k[16];
        key_sched(key,ks,seed_k);

        krng.seed(
            seed_k[ 0],seed_k[ 1],seed_k[ 2],seed_k[ 3],
            seed_k[ 4],seed_k[ 5],seed_k[ 6],seed_k[ 7],
            seed_k[ 8],seed_k[ 9],seed_k[10],seed_k[11],
            seed_k[12],seed_k[13],seed_k[14],seed_k[15]
        );
        std::cout << "[decrypt] Test krng(): " << krng() << "\n";

        // do decryption...
    }
};

1 个答案:

答案 0 :(得分:3)

编辑3:

quadrant中有初始化声明 uint32_t mx[16];

应该改为

uint32_t mx[16]={0};

cipher

使用这种类型的函数key长度预计为16.如果它少于那么你最终得到未定义的变量。

此函数仅初始化4个字符:

std::string key = "Key";

请改为尝试:

char key[16] = { 0 };
strcpy(key, "Key");

确认字符串小于16(为nul终结符留出空间)。这种方式密钥总是"Key\0\0\0\0\0\0\0\0\0\0\0\0\0"

考虑这个功能:

//Key length: 256 bits = 32 bytes
static void key_sched(const char* key,uint32_t ks,uint32_t s_k[16])     
{
    uint32_t i, j;
    int ix, iy;
    uint8_t tk[2*ks];
    uint32_t s_aux[16];
    ...
}

首先,您评论“密钥长度:256位= 32字节”,但在这种情况下,您显然需要16个字节。

其次,s_aux未初始化。似乎部分仍然没有初始化。将其更改为uint32_t s_aux[16]={0};

其他变量也应该初始化。例如:

int main()
{
    std::string ptx = "Plaintext";
    char key[16] = { 0 };
    strcpy(key, "Key");

    uint8_t* encr = 0;
    uint8_t* decr = 0;
    uint32_t esiz = 0;

    cipher::encrypt(ptx.c_str(), ptx.length(), encr, key, 16);
    cipher::decrypt(encr, esiz, decr, key, 16);
}

<小时/> 编辑:使用此函数to_hexstring检查seed_k

的内容
std::string to_hexstring(const uint32_t* buf, int buflen)
{
    std::string result;
    for (int i = 0; i < buflen; i++)
    {
        char temp[16];
        sprintf_s(temp, "%08X-", buf[i]);
        result += temp;
    }
    return result;
}

进行以下更改:

static void encrypt(const char*, uint32_t, uint8_t*, const char* key, uint32_t ks)
{
    std::cout << "Key used: " << key << "\n";
    uint32_t seed_k[16];
    key_sched(key, ks, seed_k);
    cout << to_hexstring(seed_k, 16) << endl;//<== Add this here
    ...
}

static void decrypt(uint8_t*, uint32_t, uint8_t*, const char* key, uint32_t ks)
{
    std::cout << "Key used: " << key << "\n";
    uint32_t seed_k[16];
    key_sched(key, ks, seed_k);
    cout << to_hexstring(seed_k, 16) << endl;//<== Add this here
    ...
}

现在您应该能够检查seed_k

的内容

seed_k后来输入quadrant,如果seed_k不相同,则quadrant结果也不相同。