Beispiel #1
0
int PHS_Fast(
	      void   *out,    size_t       outlen,
	const void   *in,     size_t       inlen,
	const void   *salt,   size_t       saltlen,
	unsigned int  t_cost, unsigned int m_cost)
{
	const uint64_t statelen = 256;
	const int      rounds   = 4;

	uint64_t s[statelen] = {0};

	if (outlen > 32 || t_cost != 100000 || m_cost != 0)
	{
		return 1;
	}

	memmove(s, in, inlen);
	memmove(s + (inlen / 8) + 1, salt, saltlen);
	s[statelen - 3] = outlen;
	s[statelen - 2] = inlen;
	s[statelen - 1] = saltlen;
	stir(s, statelen, rounds * 2);

	uint64_t hash[4];
	// generated from calling "PHS_break(t_cost=100000, m_cost=0, outlen=32, printXors=true)"
	hash[0] = s[0]^s[2]^s[3]^s[7]^s[8]^s[9]^s[12]^s[13]^s[16]^s[20]^s[22]^s[23]^s[24]^s[25]^s[26]^s[27]^s[33]^s[34]^s[35]^s[36]^s[37]^s[38]^s[39]^s[40]^s[42]^s[48]^s[49]^s[54]^s[56]^s[57]^s[59]^s[62]^s[63]^s[64]^s[65]^s[66]^s[67]^s[68]^s[69]^s[79]^s[81]^s[85]^s[88]^s[90]^s[91]^s[92]^s[97]^s[98]^s[99]^s[101]^s[102]^s[103]^s[104]^s[108]^s[110]^s[112]^s[113]^s[116]^s[117]^s[118]^s[119]^s[120]^s[121]^s[122]^s[123]^s[124]^s[125]^s[126]^s[127]^s[128]^s[129]^s[131]^s[132]^s[133]^s[134]^s[135]^s[136]^s[137]^s[138]^s[139]^s[142]^s[144]^s[145]^s[146]^s[148]^s[151]^s[152]^s[153]^s[154]^s[156]^s[157]^s[158]^s[159]^s[160]^s[162]^s[169]^s[171]^s[172]^s[173]^s[175]^s[179]^s[180]^s[186]^s[188]^s[196]^s[202]^s[205]^s[207]^s[210]^s[211]^s[212]^s[213]^s[214]^s[216]^s[217]^s[218]^s[219]^s[221]^s[225]^s[227]^s[229]^s[233]^s[234]^s[235]^s[236]^s[239]^s[241]^s[242]^s[248]^s[249]^s[255];
	hash[1] = s[0]^s[3]^s[4]^s[8]^s[9]^s[10]^s[13]^s[14]^s[17]^s[21]^s[23]^s[24]^s[25]^s[26]^s[27]^s[28]^s[34]^s[35]^s[36]^s[37]^s[38]^s[39]^s[40]^s[41]^s[43]^s[49]^s[50]^s[55]^s[57]^s[58]^s[60]^s[63]^s[64]^s[65]^s[66]^s[67]^s[68]^s[69]^s[70]^s[80]^s[82]^s[86]^s[89]^s[91]^s[92]^s[93]^s[98]^s[99]^s[100]^s[102]^s[103]^s[104]^s[105]^s[109]^s[111]^s[113]^s[114]^s[117]^s[118]^s[119]^s[120]^s[121]^s[122]^s[123]^s[124]^s[125]^s[126]^s[127]^s[128]^s[129]^s[130]^s[132]^s[133]^s[134]^s[135]^s[136]^s[137]^s[138]^s[139]^s[140]^s[143]^s[145]^s[146]^s[147]^s[149]^s[152]^s[153]^s[154]^s[155]^s[157]^s[158]^s[159]^s[160]^s[161]^s[163]^s[170]^s[172]^s[173]^s[174]^s[176]^s[180]^s[181]^s[187]^s[189]^s[197]^s[203]^s[206]^s[208]^s[211]^s[212]^s[213]^s[214]^s[215]^s[217]^s[218]^s[219]^s[220]^s[222]^s[226]^s[228]^s[230]^s[234]^s[235]^s[236]^s[237]^s[240]^s[242]^s[243]^s[249]^s[250];
	hash[2] = s[4]^s[5]^s[9]^s[10]^s[11]^s[14]^s[15]^s[18]^s[22]^s[24]^s[25]^s[26]^s[27]^s[28]^s[29]^s[35]^s[36]^s[37]^s[38]^s[39]^s[40]^s[41]^s[42]^s[44]^s[50]^s[51]^s[56]^s[58]^s[59]^s[61]^s[64]^s[65]^s[66]^s[67]^s[68]^s[69]^s[70]^s[71]^s[81]^s[83]^s[87]^s[90]^s[92]^s[93]^s[94]^s[99]^s[100]^s[101]^s[103]^s[104]^s[105]^s[106]^s[110]^s[112]^s[114]^s[115]^s[118]^s[119]^s[120]^s[121]^s[122]^s[123]^s[124]^s[125]^s[126]^s[127]^s[128]^s[129]^s[130]^s[131]^s[133]^s[134]^s[135]^s[136]^s[137]^s[138]^s[139]^s[140]^s[141]^s[144]^s[146]^s[147]^s[148]^s[150]^s[153]^s[154]^s[155]^s[156]^s[158]^s[159]^s[160]^s[161]^s[162]^s[164]^s[171]^s[173]^s[174]^s[175]^s[177]^s[181]^s[182]^s[188]^s[190]^s[198]^s[204]^s[207]^s[209]^s[212]^s[213]^s[214]^s[215]^s[216]^s[218]^s[219]^s[220]^s[221]^s[223]^s[227]^s[229]^s[231]^s[235]^s[236]^s[237]^s[238]^s[241]^s[243]^s[244]^s[250]^s[251];
	hash[3] = s[1]^s[5]^s[6]^s[10]^s[11]^s[12]^s[15]^s[16]^s[19]^s[23]^s[25]^s[26]^s[27]^s[28]^s[29]^s[30]^s[36]^s[37]^s[38]^s[39]^s[40]^s[41]^s[42]^s[43]^s[45]^s[51]^s[52]^s[57]^s[59]^s[60]^s[62]^s[65]^s[66]^s[67]^s[68]^s[69]^s[70]^s[71]^s[72]^s[82]^s[84]^s[88]^s[91]^s[93]^s[94]^s[95]^s[100]^s[101]^s[102]^s[104]^s[105]^s[106]^s[107]^s[111]^s[113]^s[115]^s[116]^s[119]^s[120]^s[121]^s[122]^s[123]^s[124]^s[125]^s[126]^s[127]^s[128]^s[129]^s[130]^s[131]^s[132]^s[134]^s[135]^s[136]^s[137]^s[138]^s[139]^s[140]^s[141]^s[142]^s[145]^s[147]^s[148]^s[149]^s[151]^s[154]^s[155]^s[156]^s[157]^s[159]^s[160]^s[161]^s[162]^s[163]^s[165]^s[172]^s[174]^s[175]^s[176]^s[178]^s[182]^s[183]^s[189]^s[191]^s[199]^s[205]^s[208]^s[210]^s[213]^s[214]^s[215]^s[216]^s[217]^s[219]^s[220]^s[221]^s[222]^s[224]^s[228]^s[230]^s[232]^s[236]^s[237]^s[238]^s[239]^s[242]^s[244]^s[245]^s[251]^s[252];
	memmove(out, hash, outlen);
	return 0;
}
/**
 * \brief Generates random bytes into a caller-supplied buffer.
 *
 * \param data Points to the buffer to fill with random bytes.
 * \param len Number of bytes to generate.
 *
 * Calling this function will decrease the amount of entropy in the
 * random number pool by \a len * 8 bits.  If there isn't enough
 * entropy, then this function will still return \a len bytes of
 * random data generated from what entropy it does have.
 *
 * If the application requires a specific amount of entropy before
 * generating important values, the available() function can be
 * polled to determine when sufficient entropy is available.
 *
 * \sa available(), stir()
 */
void RNGClass::rand(uint8_t *data, size_t len)
{
    // Make sure that the RNG is initialized in case the application
    // forgot to call RNG.begin() at startup time.
    if (!initialized)
        begin(0);

    // Decrease the amount of entropy in the pool.
    if (len > (credits / 8u))
        credits = 0;
    else
        credits -= len * 8;

    // If we have pending TRNG data from the loop() function,
    // then force a stir on the state.  Otherwise mix in some
    // fresh data from the TRNG because it is possible that
    // the application forgot to call RNG.loop().
    if (trngPending) {
        stir(0, 0, 0);
        trngPending = 0;
        trngPosn = 0;
    } else {
        mixTRNG();
    }

    // Generate the random data.
    uint8_t count = 0;
    while (len > 0) {
        // Force a rekey if we have generated too many blocks in this request.
        if (count >= RNG_REKEY_BLOCKS) {
            rekey();
            count = 1;
        } else {
            ++count;
        }

        // Increment the low counter word and generate a new keystream block.
        ++(block[12]);
        ChaCha::hashCore(stream, block, RNG_ROUNDS);

        // Copy the data to the return buffer.
        if (len < 64) {
            memcpy(data, stream, len);
            break;
        } else {
            memcpy(data, stream, 64);
            data += 64;
            len -= 64;
        }
    }

    // Force a rekey after every request.
    rekey();
}
void ARC4RandomNumberGenerator::stirIfNeeded()
{
    if (m_count <= 0)
        stir();
}
/**
 * \brief Run periodic housekeeping tasks on the random number generator.
 *
 * This function must be called on a regular basis from the application's
 * main "loop()" function.
 */
void RNGClass::loop()
{
    // Stir in the entropy from all registered noise sources.
    for (uint8_t posn = 0; posn < count; ++posn)
        noiseSources[posn]->stir();

#if defined(RNG_DUE_TRNG)
    // If there is data available from the Arudino Due's TRNG, then XOR
    // it with the state block and increase the entropy credit.  We don't
    // call stir() yet because that will seriously slow down the system
    // given how fast the TRNG is.  Instead we save up the XOR'ed TRNG
    // data until the next rand() call and then hash it to generate the
    // desired output.
    //
    // The CPU documentation claims that the TRNG output is very good so
    // this should only make the pool more and more random as time goes on.
    // However there is a risk that the CPU manufacturer was pressured by
    // government or intelligence agencies to insert a back door that
    // generates predictable output.  Or the manufacturer was overly
    // optimistic about their TRNG design and it is actually flawed in a
    // way they don't realise.
    //
    // If you are concerned about such threats, then make sure to mix in
    // data from other noise sources.  By hashing together the TRNG with
    // the other noise data, rand() should produce unpredictable data even
    // if one of the sources is actually predictable.
    if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
        block[4 + trngPosn] ^= REG_TRNG_ODATA;
        if (++trngPosn >= 12)
            trngPosn = 0;
        if (credits < RNG_MAX_CREDITS) {
            // Credit 1 bit of entropy for the word.  The TRNG should be
            // better than this but it is so fast that we want to collect
            // up more data before passing it to the application.
            ++credits;
        }
        trngPending = 1;
    }
#elif defined(RNG_WORD_TRNG)
    // Read a word from the TRNG and XOR it into the state.
    block[4 + trngPosn] ^= RNG_WORD_TRNG_GET();
    if (++trngPosn >= 12)
        trngPosn = 0;
    if (credits < RNG_MAX_CREDITS) {
        // Credit 1 bit of entropy for the word.  The TRNG should be
        // better than this but it is so fast that we want to collect
        // up more data before passing it to the application.
        ++credits;
    }
    trngPending = 1;
#elif defined(RNG_WATCHDOG)
    // Read the 32 bit buffer from the WDT interrupt.
    cli();
    if (outBits >= 32) {
        uint32_t value = hash;
        hash = 0;
        outBits = 0;
        sei();

        // Final steps of the Jenkin's one-at-a-time hash function.
        // https://en.wikipedia.org/wiki/Jenkins_hash_function
        value += leftShift3(value);
        value ^= rightShift11(value);
        value += leftShift15(value);

        // Credit 1 bit of entropy for each byte of input.  It can take
        // between 30 and 40 seconds to accumulate 256 bits of credit.
        credits += 4;
        if (credits > RNG_MAX_CREDITS)
            credits = RNG_MAX_CREDITS;

        // XOR the word with the state.  Stir once we accumulate 48 bytes,
        // which happens about once every 6.4 seconds.
        block[4 + trngPosn] ^= value;
        if (++trngPosn >= 12) {
            trngPosn = 0;
            trngPending = 0;
            stir(0, 0, 0);
        } else {
            trngPending = 1;
        }
    } else {
        sei();
    }
#endif

    // Save the seed if the auto-save timer has expired.
    if ((millis() - timer) >= timeout)
        save();
}
/**
 * \brief Initializes the random number generator.
 *
 * \param tag A string that is stirred into the random pool at startup;
 * usually this should be a value that is unique to the application and
 * version such as "MyApp 1.0" so that different applications do not
 * generate the same sequence of values upon first boot.
 *
 * This function should be followed by calls to addNoiseSource() to
 * register the application's noise sources.
 *
 * \sa addNoiseSource(), stir(), save()
 */
void RNGClass::begin(const char *tag)
{
    // Bail out if we have already done this.
    if (initialized)
        return;

    // Initialize the ChaCha20 input block from the saved seed.
    memcpy_P(block, tagRNG, sizeof(tagRNG));
    memcpy_P(block + 4, initRNG, sizeof(initRNG));
#if defined(RNG_EEPROM)
    int address = RNG_EEPROM_ADDRESS;
    eeprom_read_block(stream, (const void *)address, SEED_SIZE);
    if (crypto_crc8('S', stream, SEED_SIZE - 1) ==
            ((const uint8_t *)stream)[SEED_SIZE - 1]) {
        // We have a saved seed: XOR it with the initialization block.
        // Note: the CRC-8 value is included.  No point throwing it away.
        for (int posn = 0; posn < 12; ++posn)
            block[posn + 4] ^= stream[posn];
    }
#elif defined(RNG_DUE_TRNG)
    // Do we have a seed saved in the last page of flash memory on the Due?
    if (crypto_crc8('S', ((const uint32_t *)RNG_SEED_ADDR) + 1, SEED_SIZE)
            == ((const uint32_t *)RNG_SEED_ADDR)[0]) {
        // XOR the saved seed with the initialization block.
        for (int posn = 0; posn < 12; ++posn)
            block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1];
    }

    // If the device has just been reprogrammed, there will be no saved seed.
    // XOR the initialization block with some output from the CPU's TRNG
    // to permute the state in a first boot situation after reprogramming.
    pmc_enable_periph_clk(ID_TRNG);
    REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
    REG_TRNG_IDR = TRNG_IDR_DATRDY; // Disable interrupts - we will poll.
    mixTRNG();
#endif
#if defined(RNG_ESP_NVS)
    // Do we have a seed saved in ESP non-volatile storage (NVS)?
    nvs_handle handle = 0;
    if (nvs_open("rng", NVS_READONLY, &handle) == 0) {
        size_t len = 0;
        if (nvs_get_blob(handle, "seed", NULL, &len) == 0 && len == SEED_SIZE) {
            uint32_t seed[12];
            if (nvs_get_blob(handle, "seed", seed, &len) == 0) {
                for (int posn = 0; posn < 12; ++posn)
                    block[posn + 4] ^= seed[posn];
            }
            clean(seed);
        }
        nvs_close(handle);
    }
#endif
#if defined(RNG_WORD_TRNG)
    // Mix in some output from a word-based TRNG to initialize the state.
    mixTRNG();
#endif

    // No entropy credits for the saved seed.
    credits = 0;

    // Trigger an automatic save once the entropy credits max out.
    firstSave = 1;

    // Rekey the random number generator immediately.
    rekey();

    // Stir in the supplied tag data but don't credit any entropy to it.
    if (tag)
        stir((const uint8_t *)tag, strlen(tag));

#if defined(RNG_DUE_TRNG)
    // Stir in the unique identifier for the CPU so that different
    // devices will give different outputs even without seeding.
    stirUniqueIdentifier();
#elif defined(ESP8266)
    // ESP8266's have a 32-bit CPU chip ID and 32-bit flash chip ID
    // that we can use as a device unique identifier.
    uint32_t ids[2];
    ids[0] = ESP.getChipId();
    ids[1] = ESP.getFlashChipId();
    stir((const uint8_t *)ids, sizeof(ids));
#elif defined(ESP32)
    // ESP32's have a MAC address that can be used as a device identifier.
    uint64_t mac = ESP.getEfuseMac();
    stir((const uint8_t *)&mac, sizeof(mac));
#else
    // AVR devices don't have anything like a serial number so it is
    // difficult to make every device unique.  Use the compilation
    // time and date to provide a little randomness across applications
    // if not across devices running the same pre-compiled application.
    tag = __TIME__ __DATE__;
    stir((const uint8_t *)tag, strlen(tag));
#endif

#if defined(RNG_WATCHDOG)
    // Disable interrupts and reset the watchdog.
    cli();
    wdt_reset();

    // Clear the "reset due to watchdog" flag.
    MCUSR &= ~(1 << WDRF);

    // Enable the watchdog with the smallest duration (16ms)
    // and interrupt-only mode.
    _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
    _WD_CONTROL_REG = (1 << WDIE);

    // Re-enable interrupts.  The watchdog should be running.
    sei();
#endif

    // Re-save the seed to obliterate the previous value and to ensure
    // that if the system is reset without a call to save() that we won't
    // accidentally generate the same sequence of random data again.
    save();

    // The RNG has now been initialized.
    initialized = 1;
}
Beispiel #6
0
/**
 * \brief Initializes the random number generator.
 *
 * \param tag A string that is stirred into the random pool at startup;
 * usually this should be a value that is unique to the application and
 * version such as "MyApp 1.0" so that different applications do not
 * generate the same sequence of values upon first boot.
 * \param eepromAddress The EEPROM address to load the previously saved
 * seed from and to save new seeds when save() is called.  There must be
 * at least SEED_SIZE (49) bytes of EEPROM space available at the address.
 *
 * This function should be followed by calls to addNoiseSource() to
 * register the application's noise sources.
 *
 * The \a eepromAddress is ignored on the Arduino Due.  The seed is instead
 * stored in the last page of system flash memory.
 *
 * \sa addNoiseSource(), stir(), save()
 */
void RNGClass::begin(const char *tag, int eepromAddress)
{
    // Save the EEPROM address for use by save().
    address = eepromAddress;

    // Initialize the ChaCha20 input block from the saved seed.
    memcpy_P(block, tagRNG, sizeof(tagRNG));
    memcpy_P(block + 4, initRNG, sizeof(initRNG));
#if defined(RNG_EEPROM)
    if (eeprom_read_byte((const uint8_t *)address) == 'S') {
        // We have a saved seed: XOR it with the initialization block.
        for (int posn = 0; posn < 12; ++posn) {
            block[posn + 4] ^=
                eeprom_read_dword((const uint32_t *)(address + posn * 4 + 1));
        }
    }
#elif defined(RNG_DUE_TRNG)
    // Do we have a seed saved in the last page of flash memory on the Due?
    int posn, counter;
    if (((const uint32_t *)RNG_SEED_ADDR)[0] == 'S') {
        // XOR the saved seed with the initialization block.
        for (posn = 0; posn < 12; ++posn)
            block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1];
    }

    // If the device has just been reprogrammed, there will be no saved seed.
    // XOR the initialization block with some output from the CPU's TRNG
    // to permute the state in a first boot situation after reprogramming.
    pmc_enable_periph_clk(ID_TRNG);
    REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
    REG_TRNG_IDR = TRNG_IDR_DATRDY; // Disable interrupts - we will poll.
    for (posn = 0; posn < 12; ++posn) {
        // According to the documentation the TRNG should produce a new
        // 32-bit random value every 84 clock cycles.  If it still hasn't
        // produced a value after 200 iterations, then assume that the
        // TRNG is not producing output and stop.
        for (counter = 0; counter < 200; ++counter) {
            if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
                break;
        }
        if (counter >= 200)
            break;
        block[posn + 4] ^= REG_TRNG_ODATA;
    }
#endif

    // No entropy credits for the saved seed.
    credits = 0;

    // Trigger an automatic save once the entropy credits max out.
    firstSave = 1;

    // Rekey the random number generator immediately.
    rekey();

    // Stir in the supplied tag data but don't credit any entropy to it.
    if (tag)
        stir((const uint8_t *)tag, strlen(tag));

#if defined(RNG_DUE_TRNG)
    // Stir in the unique identifier for the CPU so that different
    // devices will give different outputs even without seeding.
    stirUniqueIdentifier();
#endif

    // Re-save the seed to obliterate the previous value and to ensure
    // that if the system is reset without a call to save() that we won't
    // accidentally generate the same sequence of random data again.
    save();
}