/**
 * \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();
}
/**
 * \brief Saves the random seed to EEPROM.
 *
 * During system startup, noise sources typically won't have accumulated
 * much entropy.  But startup is usually the time when the system most
 * needs to generate random data for session keys, IV's, and the like.
 *
 * The purpose of this function is to pass some of the accumulated entropy
 * from one session to the next after a loss of power.  Thus, once the system
 * has been running for a while it will get progressively better at generating
 * random values and the accumulated entropy will not be completely lost.
 *
 * Normally it isn't necessary to call save() directly.  The loop() function
 * will automatically save the seed on a periodic basis (default of 1 hour).
 *
 * The seed that is saved is generated in such a way that it cannot be used
 * to predict random values that were generated previously or subsequently
 * in the current session.  So a compromise of the EEPROM contents of a
 * captured device should not result in compromise of random values
 * that have already been generated.  However, if power is lost and the
 * system restarted, then there will be a short period of time where the
 * random state will be predictable from the seed.  For this reason it is
 * very important to stir() in new noise data at startup.
 *
 * \sa loop(), stir()
 */
void RNGClass::save()
{
    // Generate random data from the current state and save
    // that as the seed.  Then force a rekey.
    ++(block[12]);
    ChaCha::hashCore(stream, block, RNG_ROUNDS);
#if defined(RNG_EEPROM)
    // We shorten the seed from 48 bytes to 47 to leave room for
    // the CRC-8 value.  We do this to align the data on an 8-byte
    // boundary in EERPOM.
    int address = RNG_EEPROM_ADDRESS;
    eeprom_write_block(stream, (void *)address, SEED_SIZE - 1);
    eeprom_write_byte((uint8_t *)(address + SEED_SIZE - 1),
                      crypto_crc8('S', stream, SEED_SIZE - 1));
#elif defined(RNG_DUE_TRNG)
    unsigned posn;
    ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8('S', stream, SEED_SIZE);
    for (posn = 0; posn < 12; ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
    for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
    eraseAndWriteSeed();
#elif defined(RNG_ESP_NVS)
    // Save the seed into ESP non-volatile storage (NVS).
    nvs_handle handle = 0;
    if (nvs_open("rng", NVS_READWRITE, &handle) == 0) {
        nvs_erase_all(handle);
        nvs_set_blob(handle, "seed", stream, SEED_SIZE);
        nvs_commit(handle);
        nvs_close(handle);
    }
#endif
    rekey();
    timer = millis();
}
Exemple #3
0
static void
extract_data(FState * st, unsigned count, unsigned char *dst)
{
    unsigned	n;
    unsigned	block_nr = 0;
    pid_t	pid = getpid();

    /* Should we reseed? */
    if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0)
	if (enough_time_passed(st))
	    reseed(st);

    /* Do some randomization on first call */
    if (!st->tricks_done)
	startup_tricks(st);

    /* If we forked, force a reseed again */
    if (pid != st->pid) {
	st->pid = pid;
	reseed(st);
    }

    while (count > 0)
    {
	/* produce bytes */
	encrypt_counter(st, st->result);

	/* copy result */
	if (count > CIPH_BLOCK)
	    n = CIPH_BLOCK;
	else
	    n = count;
	memcpy(dst, st->result, n);
	dst += n;
	count -= n;

	/* must not give out too many bytes with one key */
	block_nr++;
	if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
	{
	    rekey(st);
	    block_nr = 0;
	}
    }
    /* Set new key for next request. */
    rekey(st);
}
Exemple #4
0
size_t ANSI_X931_RNG::reseed_with_sources(Entropy_Sources& srcs,
                                          size_t poll_bits,
                                          std::chrono::milliseconds poll_timeout)
   {
   size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
   rekey();
   return bits;
   }
Exemple #5
0
/**
 * \brief Stirs additional entropy data into the random pool.
 *
 * \param data Points to the additional data to be stirred in.
 * \param len Number of bytes to be stirred in.
 * \param credit The number of bits of entropy to credit for the
 * data that is stirred in.  Note that this is bits, not bytes.
 *
 * The maximum credit allowed is \a len * 8 bits, indicating that
 * every bit in the input \a data is good and random.  Practical noise
 * sources are rarely that good, so \a credit will usually be smaller.
 * For example, to credit 2 bits of entropy per byte, the function
 * would be called as follows:
 *
 * \code
 * RNG.stir(noise_data, noise_bytes, noise_bytes * 2);
 * \endcode
 *
 * If \a credit is zero, then the \a data will be stirred in but no
 * entropy credit is given.  This is useful for static values like
 * serial numbers and MAC addresses that are different between
 * devices but highly predictable.
 *
 * \sa loop()
 */
void RNGClass::stir(const uint8_t *data, size_t len, unsigned int credit)
{
    // Increase the entropy credit.
    if ((credit / 8) >= len && len)
        credit = len * 8;
    if ((unsigned int)(RNG_MAX_CREDITS - credits) > credit)
        credits += credit;
    else
        credits = RNG_MAX_CREDITS;

    // Process the supplied input data.
    if (len > 0) {
        // XOR the data with the ChaCha input block in 48 byte
        // chunks and rekey the ChaCha cipher for each chunk to mix
        // the data in.  This should scatter any "true entropy" in
        // the input across the entire block.
        while (len > 0) {
            size_t templen = len;
            if (templen > 48)
                templen = 48;
            uint8_t *output = ((uint8_t *)block) + 16;
            len -= templen;
            while (templen > 0) {
				//Serial.println(*data); //Debug to view random data in real-time
                *output++ ^= *data++;
                --templen;
            }
            rekey();
        }
    } else {
        // There was no input data, so just force a rekey so we
        // get some mixing of the state even without new data.
        rekey();
    }

    // Save if this is the first time we have reached max entropy.
    // This provides some protection if the system is powered off before
    // the first auto-save timeout occurs.
    if (firstSave && credits >= RNG_MAX_CREDITS) {
        firstSave = 0;
        save();
    }
}
Exemple #6
0
int32_t tc_hmac_set_key(TCHmacState_t ctx,
			const uint8_t *key,
			uint32_t key_size)
{
	/* input sanity check: */
	if (ctx == (TCHmacState_t) 0 ||
	    key == (const uint8_t *) 0 ||
	    key_size == 0) {
		return TC_FAIL;
	}

	const uint8_t dummy_key[key_size];
	struct tc_hmac_state_struct dummy_state;

	if (key_size <= TC_SHA256_BLOCK_SIZE) {
		/*
		 * The next three lines consist of dummy calls just to avoid
		 * certain timing attacks. Without these dummy calls,
		 * adversaries would be able to learn whether the key_size is
		 * greater than TC_SHA256_BLOCK_SIZE by measuring the time
		 * consumed in this process.
		 */
		(void)tc_sha256_init(&dummy_state.hash_state);
		(void)tc_sha256_update(&dummy_state.hash_state,
				       dummy_key,
				       key_size);
		(void)tc_sha256_final(&dummy_state.key[TC_SHA256_DIGEST_SIZE],
				      &dummy_state.hash_state);

		/* Actual code for when key_size <= TC_SHA256_BLOCK_SIZE: */
		rekey(ctx->key, key, key_size);
	} else {
		(void)tc_sha256_init(&ctx->hash_state);
		(void)tc_sha256_update(&ctx->hash_state, key, key_size);
		(void)tc_sha256_final(&ctx->key[TC_SHA256_DIGEST_SIZE],
				      &ctx->hash_state);
		rekey(ctx->key,
		      &ctx->key[TC_SHA256_DIGEST_SIZE],
		      TC_SHA256_DIGEST_SIZE);
	}

	return TC_SUCCESS;
}
Exemple #7
0
/*
 * Fortuna relies on AES standing known-plaintext attack.
 * In case it does not, slow down the attacker by initialising
 * the couter to random value.
 */
static void
init_counter(FState * st)
{
	/* Use next block as counter. */
	encrypt_counter(st, st->counter);

	/* Hide the key. */
	rekey(st);

	/* The counter can be shuffled only once. */
	st->counter_init = 1;
}
Exemple #8
0
static void
extract_data(FState * st, unsigned count, uint8 *dst)
{
	unsigned	n;
	unsigned	block_nr = 0;

	/* Can we reseed? */
	if (st->pool0_bytes >= POOL0_FILL && !too_often(st))
		reseed(st);

	/* Is counter initialized? */
	if (!st->counter_init)
		init_counter(st);

	while (count > 0)
	{
		/* produce bytes */
		encrypt_counter(st, st->result);

		/* copy result */
		if (count > CIPH_BLOCK)
			n = CIPH_BLOCK;
		else
			n = count;
		memcpy(dst, st->result, n);
		dst += n;
		count -= n;

		/* must not give out too many bytes with one key */
		block_nr++;
		if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
		{
			rekey(st);
			block_nr = 0;
		}
	}
	/* Set new key for next request. */
	rekey(st);
}
Exemple #9
0
static void extract_data(FState *st, unsigned count, uint8_t *dst)
{
	unsigned n;
	unsigned block_nr = 0;

	/* Should we reseed? */
	if (st->pool0Bytes >= pool0Fill || st->reseedCount == 0)
		if (enough_time_passed(st))
			reseed(st);

	/* Do some randomization on first call */
	if (!st->tricksDone)
		startup_tricks(st);

	while (count > 0) {
		/* produce bytes */
		encrypt_counter(st, st->result);

		/* copy result */
		if (count > ciphBlock)
			n = ciphBlock;
		else
			n = count;
		memmove(dst, st->result, n);
		dst += n;
		count -= n;

		/* must not give out too many bytes with one key */
		block_nr++;
		if (block_nr > (reseedBytes / ciphBlock)) {
			rekey(st);
			block_nr = 0;
		}
	}
	/* Set new key for next request. */
	rekey(st);
}
Exemple #10
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)
{
    // Decrease the amount of entropy in the pool.
    if (len > (credits / 8))
        credits = 0;
    else
        credits -= len * 8;

    // 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();
}
Exemple #11
0
/**
 * \brief Saves the random seed to EEPROM.
 *
 * During system startup, noise sources typically won't have accumulated
 * much entropy.  But startup is usually the time when the system most
 * needs to generate random data for session keys, IV's, and the like.
 *
 * The purpose of this function is to pass some of the accumulated entropy
 * from one session to the next after a loss of power.  Thus, once the system
 * has been running for a while it will get progressively better at generating
 * random values and the accumulated entropy will not be completely lost.
 *
 * Normally it isn't necessary to call save() directly.  The loop() function
 * will automatically save the seed on a periodic basis (default of 1 hour).
 *
 * The seed that is saved is generated in such a way that it cannot be used
 * to predict random values that were generated previously or subsequently
 * in the current session.  So a compromise of the EEPROM contents of a
 * captured device should not result in compromise of random values
 * that have already been generated.  However, if power is lost and the
 * system restarted, then there will be a short period of time where the
 * random state will be predictable from the seed.  For this reason it is
 * very important to stir() in new noise data at startup.
 *
 * \sa loop(), stir()
 */
void RNGClass::save()
{
    // Generate random data from the current state and save
    // that as the seed.  Then force a rekey.
    ++(block[12]);
    ChaCha::hashCore(stream, block, RNG_ROUNDS);
#if defined(RNG_EEPROM)
    eeprom_write_block(stream, (void *)(address + 1), 48);
    eeprom_update_byte((uint8_t *)address, 'S');
#elif defined(RNG_DUE_TRNG)
    unsigned posn;
    ((uint32_t *)(RNG_SEED_ADDR))[0] = 'S';
    for (posn = 0; posn < 12; ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
    for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
    eraseAndWriteSeed();
#endif
    rekey();
    timer = millis();
}
Exemple #12
0
/*
 * Hide public constants. (counter, pools > 0)
 *
 * This can also be viewed as spreading the startup
 * entropy over all of the components.
 */
static void startup_tricks(FState *st)
{
	int i;
	uint8_t buf[block];

	/* Use next block as counter. */
	encrypt_counter(st, st->counter);

	/* Now shuffle pools, excluding #0 */
	for (i = 1; i < numPools; i++) {
		encrypt_counter(st, buf);
		encrypt_counter(st, buf + ciphBlock);
		md_update(&st->pool[i], buf, block);
	}
	memset(buf, 0, block);

	/* Hide the key. */
	rekey(st);

	/* This can be done only once. */
	st->tricksDone = 1;
}
Exemple #13
0
/*
 * Hide public constants. (counter, pools > 0)
 *
 * This can also be viewed as spreading the startup
 * entropy over all of the components.
 */
static void
startup_tricks(FState *st)
{
	int			i;
	uint8		buf[BLOCK];

	/* Use next block as counter. */
	encrypt_counter(st, st->counter);

	/* Now shuffle pools, excluding #0 */
	for (i = 1; i < NUM_POOLS; i++)
	{
		encrypt_counter(st, buf);
		encrypt_counter(st, buf + CIPH_BLOCK);
		md_update(&st->pool[i], buf, BLOCK);
	}
	px_memset(buf, 0, BLOCK);

	/* Hide the key. */
	rekey(st);

	/* This can be done only once. */
	st->tricks_done = 1;
}
Exemple #14
0
void main(void)
{
// Declare your local variables here
//eeprom *int ee_int;
float time_filter;
// Reset Source checking
if (MCUCSR & 1)
{/* Power-on Reset*/MCUCSR&=0xE0;}
else if (MCUCSR & 2)
{/* External Reset*/MCUCSR&=0xE0;/* Place your code here*/}
else if (MCUCSR & 4)
{// Brown-Out Reset
   MCUCSR&=0xE0;/* Place your code here*/}
else if (MCUCSR & 8){// Watchdog Reset
   MCUCSR&=0xE0;/* Place your code here*/}
else if (MCUCSR & 0x10){// JTAG Reset
   MCUCSR&=0xE0;/* Place your code here*/};

PORTA=0xFF;DDRA=0xFF;
PORTB=0x00;DDRB=0xB3;
PORTC=0b11111000;DDRC=0b11111011;
PORTD=0b11110000;DDRD=0x00;

TCCR0=0x02;TCNT0=TCNT0_reload;OCR0=0x00;

TCCR1A=0x00;TCCR1B=0x05;TCNT1H=0x00;TCNT1L=0x01;
ICR1H=0x00;ICR1L=0x04;OCR1AH=0x00;OCR1AL=0x02;
OCR1BH=0x00;OCR1BL=0x03;

ASSR=0x00;TCCR2=0x03;TCNT2=TCNT2_reload;OCR2=0x00;

MCUCR=0x00;MCUCSR=0x00;

TIMSK=0xFF;

UCSRA=0x00;UCSRB=0xD8;UCSRC=0x86;UBRRH=0x00;UBRRL=0x33;
ACSR=0x80;SFIOR=0x00;
SPCR=0x52;SPSR=0x00;
WDTCR=0x1F;WDTCR=0x0F;

count_register=1;
data_register=1234;
time_filter=2;
#asm("sei")
mode=0;
x=0;
start_time=sys_time;
while (1)
        {
        #asm("wdr");
        for (i=0;i<9;i++)rang[i]=0;
        if (++buf_end>8) buf_end=0;
        buf[buf_end]=read_adc();
        for (j=0;j<9;j++)
                {
                for (i=0;i<9;i++)
                        {
                        if (buf[j]<buf[i]) rang[j]--;
                        if (buf[j]>buf[i]) rang[j]++;
                        }
                }
        for(i=0;i<9;i++){if (rang[i]<0)rang[i]=0-rang[i];}
        j=0;for(i=0;i<9;i++){if (rang[j]>rang[i])j=i;}

        xx=(6-time_filter)*0.002;xx=xx*buf[j];
        yy=1-((6-time_filter)*0.002);yy=yy*x;x=xx+yy;
        adc_buf=x+0.5;
        
        if (mode==0)
                {
                hex2dec(adc_buf);
                }
                
        if (((sys_time-start_time_mode)>15000)) mode=0;
        if (mode==1)//уставка №1
                {
                set_led_on(0,0,1,1,0,0,0,0);
                set_led_off(0,0,0,1,0,0,0,0);
                if (((sys_time-start_time_mode)<5000))
                        {
                        tis='У';sot='_';des=1;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        tis=' ';sot=5;des=4;ed=3;
                        set_digit_off(' ',' ',' ',' ');
                        }
                }
        if (mode==2)//уставка №2
                {
                set_led_on(0,1,0,1,0,0,0,0);
                set_led_off(0,0,0,1,0,0,0,0);
                if (((sys_time-start_time_mode)<5000))
                        {
                        tis='У';sot='_';des=2;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        tis=' ';sot=7;des=6;ed=5;
                        set_digit_off(' ',' ',' ',' ');
                        }
                }
        if (mode==3)//время до уставки 1
                {
                if (((sys_time-start_time_mode)<5000))
                        {
                        set_led_on(0,0,1,1,0,0,0,0);
                        set_led_off(0,0,0,1,0,0,0,0);
                        tis=3;sot='_';des=1;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        tis=' ';sot=7;des=6;ed=5;
                        set_digit_off(' ',' ',' ',' ');
                        }
                }
        if (mode==4)//время до уставки 2
                {
                if (((sys_time-start_time_mode)<5000))
                        {
                        set_led_on(0,1,0,1,0,0,0,0);
                        set_led_off(0,0,0,1,0,0,0,0);
                        tis=3;sot='_';des=2;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        tis=' ';sot=7;des=6;ed=5;
                        set_digit_off(' ',' ',' ',' ');
                        }
                }
        if (mode==5)
                {
                tis=' ';sot=5;des=5;ed=' ';
                set_digit_off(' ',' ',' ',' ');
                set_led_on(0,0,1,1,0,1,0,0);
                set_led_off(0,0,0,1,0,1,0,0);
                }

        if (mode==10)
                {
                hex2dec(count_register);
                if (des==0) des='_';
                tis='a';sot='_';//des=count_register;ed=' ';
                set_digit_off(' ',' ',' ',' ');
                set_led_on(0,0,1,1,0,0,0,0);
                set_led_off(0,0,0,1,0,0,0,0);
                }

        if (mode==11)
                {
                hex2dec(data_register);
//                tis=' ';sot=1;des=2;ed=3;
                set_led_on(0,0,1,1,0,1,0,0);
                set_led_off(0,0,0,1,0,1,0,0);
                }
        
        
        if (key_plus_press==1)
                {
                start_time_mode=sys_time;
                if (count_key==0){if (mode==10)if (++count_register>MAX_REGISTER)count_register=MAX_REGISTER;}
                if ((count_key==0)||(count_key==21)||(count_key1==102))
                        {
                        if (mode==11){if (++data_register>MAX_MIN[count_register,1])data_register=MAX_MIN[count_register,1];}
                        if (count_key==0)count_key=60;if (count_key==21)count_key=20;
                        }
                rekey();
                }
        else if ((mode!=100)&&(key_enter_press==0)&&(key_mines_press==0)){count_key=0;count_key1=0;}

        if (key_mines_press==1)
                {
                start_time_mode=sys_time;
                if (count_key==0){if (mode==10)if (--count_register>MAX_REGISTER)count_register=MAX_REGISTER;}
                if ((count_key==0)||(count_key==21)||(count_key1==102))
                        {
                        if (mode==11){if (--data_register<MAX_MIN[count_register,0])data_register=MAX_MIN[count_register,0];}
                        if (count_key==0)count_key=60;if (count_key==21)count_key=20;
                        }
                rekey();
                }
        else if ((mode!=100)&&(key_enter_press==0)&&(key_plus_press==0)){count_key=0;count_key1=0;}

        if ((key_enter_press==1)&&(key_plus_press==0)&&(key_mines_press==0)&&(key_mode_press==0))
                {
                mode=100;
                ee_int=count_register*2;
                *ee_int=data_register;
                start_time_mode=sys_time;
                }
        else if (mode==100)
                {
                if ((sys_time-start_time_mode)>3250)
                        {
                        start_time_mode=sys_time;start_time=sys_time;mode=10;
                        }
                }

        if (key_mode_press_switch==1)
                {
                key_mode_press_switch=0;
                start_time_mode=sys_time;
                switch (mode)
                        {
                        case 0: mode=1;break;
                        case 1: mode=2;break;
                        case 2: mode=3;break;
                        case 3: mode=4;break;
                        case 4: mode=5;break;
                        case 5: mode=10;break;
                        case 10:mode=11;break;
                        case 11:mode=10;break;
                        case 100:mode=100;break;
                        }
                }

        if (((sys_time-start_time)>250)) 
                {
                set_digit_on(tis,sot,des,ed);
                if (mode==100)
                        {
                        set_digit_on(' ',3,'a','п');
                        set_digit_off(' ',3,'a','п');
                        set_led_on(0,0,0,0,0,0,0,0);
                        set_led_off(0,0,0,0,0,0,0,0);
                        }
                if (mode==11)
                        {
                        if((key_plus_press==1)||(key_mines_press==1)) set_digit_off(tis,sot,des,ed);
                        else set_digit_off(' ',' ',' ',' ');
                        }
                if (mode==0)
                        {
                        set_digit_off(tis,sot,des,ed);
                        set_led_on(0,0,0,1,0,1,0,0);
                        set_led_off(0,0,0,1,0,1,0,0);
                        }
                start_time=sys_time;
                }
        };
}
Exemple #15
0
/**
* Reseed the internal state
*/
void ANSI_X931_RNG::reseed(u32bit poll_bits)
   {
   prng->reseed(poll_bits);
   rekey();
   }
Exemple #16
0
void main(void)
{
// Declare your local variables here
bit flag_start_pause1,flag_start_pause2,f_m1,key_enter_press_switch1;
char min_r,min_n;
float time_pause1,time_pause2,adc_value1,adc_value3;
float data_register,k_f,adc_filter,adc_value2;


if      (MCUCSR & 0x01){/* Power-on Reset */MCUCSR&=0xE0;}
else if (MCUCSR & 0x02){/* External Reset */MCUCSR&=0xE0;}
else if (MCUCSR & 0x04){/* Brown-Out Reset*/MCUCSR&=0xE0;}
else if (MCUCSR & 0x08){/* Watchdog Reset */MCUCSR&=0xE0;}
else if (MCUCSR & 0x10){/* JTAG Reset     */MCUCSR&=0xE0;};

PORTA=0b11111111;DDRA=0b11111111;
PORTB=0b00000000;DDRB=0b10110011;
PORTC=0b11111000;DDRC=0b11111011;
PORTD=0b11110000;DDRD=0b00001000;

TCCR0=0x02;TCNT0=TCNT0_reload;OCR0=0x00;

TCCR1A=0x00;TCCR1B=0x05;TCNT1H=0x00;TCNT1L=0x01;
ICR1H=0x00;ICR1L=0x04;OCR1AH=0x00;OCR1AL=0x02;
OCR1BH=0x00;OCR1BL=0x03;

ASSR=0x00;TCCR2=0x03;TCNT2=TCNT2_reload;OCR2=0x00;

MCUCR=0x00;MCUCSR=0x00;TIMSK=0xFF;

UCSRA=0x00;UCSRB=0xD8;UCSRC=0x86;UBRRH=0x00;UBRRL=0x33;
ACSR=0x80;SFIOR=0x00;SPCR=0x52;SPSR=0x00;WDTCR=0x1F;WDTCR=0x0F;

// test:
// for (i=1;i<30;i++)
//         {
//         ee_float=&(reg[i]);
//         *ee_float=FAKTORY[i];//проверка граничных значений
//         }
// 
goto a1;

//Ожидание включения питания 
ee_float=&(reg[18]);
k_f=*ee_float;
if ((k_f>MAX_MIN[18,1])||(k_f<MAX_MIN[18,0])) k_f=FAKTORY[18];//проверка граничных значений
k_f=*ee_float;
k=k_f;i=0;
while (i<k)
        {
        if ((key_1==0)&&(key_4==0)&&(key_2==1)&&(key_3==1)) i++;
        else i=0;
        delay_ms(1000);
        }
power=1;

#asm("sei")
//Показать основные настройки
for (i=7;i<MAX_REGISTER;i++)
        {
        hex2dec(i-6);
        set_digit_on('a','_',des,ed);
        set_digit_off('a','_',des,ed);
        set_led_on(0,0,0,1,0,0,0,0);
        set_led_off(0,0,0,1,0,0,0,0);
        delay_ms(700);
        ee_float=&(reg[i]);
        k_f=*ee_float;
        if ((k_f>MAX_MIN[i,1])||(k_f<MAX_MIN[i,0])) *ee_float=FAKTORY[i];//проверка граничных значений
        k_f=*ee_float;
        if ((i==14)||(i==13)||(i==14)||(i==21)||(i==22))
                {
                k_f=k_f*100;
                set_led_on(0,0,0,1,0,1,0,0);
                set_led_off(0,0,0,1,0,1,0,0);
                }
        else 
                {
                set_led_on(0,0,0,1,0,0,0,0);
                set_led_off(0,0,0,1,0,0,0,0);
                }
        
        hex2dec(k_f);
        set_digit_on(tis,sot,des,ed);
        set_digit_off(tis,sot,des,ed);
        delay_ms(700);
        }
a1:

key_mode_press=0;
key_plus_press=0;
key_mines_press=0;
key_enter_press=0;
key_mode_press_switch=0;
key_plus_press_switch=0;
key_minus_press_switch=0;

#asm("sei")
mode=0;
x=0;
start_time=sys_time;
while (1)
        {
        if (read_reg(6)==0)buzer_buzer_en=0;
        else buzer_buzer_en=1;
        #asm("wdr");
        //измерение
        if (++buf_end>8) buf_end=0;buf[buf_end]=read_adc();min_r=9;
        //модальный фильтр
        for (j=0;j<9;j++)
                {
                rang[j]=0;
                for (i=0;i<9;i++)
                        {
                        if (i!=j)
                                {
                                if (buf[j]<buf[i]) rang[j]--;
                                if (buf[j]>buf[i]) rang[j]++;
                                }
                        }
                if (cabs(rang[j])<min_r) {min_r=cabs(rang[j]);min_n=j;}
                }
        //ФНЧ
        ee_float=&(reg[17]);
        k_f=*ee_float;
        if (k_f==0)
                {adc_filter=buf[min_n];}
        else
                {
                k_f=0.002/k_f;
                adc_filter=k_f*buf[min_n]+(1-k_f)*adc_filter;
                }
        
        //первичное преобразование
//         ee_float=&kal[0];
//         adc_value1=adc_filter+*ee_float;
//         ee_float=&kal[1];
//         adc_value1=adc_value1*(*ee_float);

        adc_value1=adc_filter*1.006/100;

        //вторичное преобразование//???????????????????????????????
        k_f=(read_reg(22)-read_reg(21))/(read_reg(14)-read_reg(13));
        adc_value2=read_reg(21)-k_f*read_reg(13)+adc_value1*k_f;
//        adc_value2=adc_value1adc_filter/100;
                
        //авария
        if (adc_value2<(read_reg(13)*(1-read_reg(15)/100))) {avaria=1;}
        else if (adc_value2>(read_reg(14)*(1+read_reg(16)/100))) {avaria=1;}
        else avaria=0;





        //уставка 1,2
        ee_float=&(reg[7]);k_f=*ee_float;//гистерезис
        ee_float=&(reg[1]);
        if (adc_value2>((*ee_float)*(1+k_f/100))) {alarm1=1;}//set_led_alarm1_on(1);//}
        else {alarm1=0;alarm_alarm1=0;flag_start_pause1=0;}//set_led_alarm1_on(0);//}
        ee_float=&(reg[2]);
        if (adc_value2>((*ee_float)*(1+k_f/100))) {alarm2=1;}//set_led_alarm2_on(1);//}
        else {alarm2=0;flag_start_pause2=0;}//set_led_alarm2_on(0);//}





        //пауза 1,2
        if (alarm_alarm1==1){relay_alarm1=1;}
        else relay_alarm1=0;
        if (alarm_alarm2==1){relay_alarm2=1;}
        else relay_alarm2=0;

        
        if ((flag_start_pause1==1))//&&(alarm_alarm1==0))
                {
                if ((sys_time-time_pause1)>(read_reg(3)*2000)){alarm_alarm1=1;}
                }
        else if (alarm1==1)
                {
                time_pause1=sys_time;
                flag_start_pause1=1;
                }
        if ((flag_start_pause2==1))//&&(alarm_alarm2==0))
                {
                if ((sys_time-time_pause2)>(read_reg(4)*2000))alarm_alarm2=1;
                }
        else if (alarm2==1)
                {
                time_pause2=sys_time;
                flag_start_pause2=1;
                }












        //возврат из меню
        if (((sys_time-start_time_mode)>read_reg(20)*2000)){mode=0;f_m1=0;}

        if ((key_enter_press_switch==1)&&(mode==0)){key_enter_press_switch=0;key_enter_press_switch1=1;}
        if ((key_enter_press_switch1==1)&&(key_enter==1))
                {
                if ((sys_time-whait_time)>3000)
                        {
                        mode=10;start_time_mode=sys_time;key_enter_press_switch1=0;
                        }
                }

        //МЕНЮ
        if (mode==0)
                {
                if (alarm_alarm2==0)
                        {

                        if (read_reg(12)==0)adc_value3=adc_value1;
                        else adc_value3=adc_value2;
                        }
                else
                        {
                        if (read_reg(12)==0)adc_value3=adc_value1;
                        else adc_value3=adc_value2;
                        }

                
                hex2dec(adc_value3*100);
                }
                
        if (mode==1)//уставка №1
                {
                set_led_on(0,0,1,1,0,0,0,0);//светодиод предупр.,норма 
                set_led_off(0,0,0,1,0,0,0,0);//светодиод норма

                if ((((sys_time-start_time_mode)<read_reg(19)*2000))&&(f_m1==0))//пока время индикации наименования
                        {
                        tis='У';sot='_';des=1;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        set_led_on(0,0,1,1,0,1,0,0);//светодиод предупр.,норма, запятая 2
                        count_register=1;
                        hex2dec(data_register*100);
                        f_m1=1;
                        }
                }
        if (mode==2)//уставка №2
                {
                set_led_on(0,1,0,1,0,0,0,0);//светодиод аварийн.,норма
                set_led_off(0,0,0,1,0,0,0,0);//светодиод норма

                if ((((sys_time-start_time_mode)<read_reg(19)*2000))&&(f_m1==0))//пока время индикации наименования
                        {
                        tis='У';sot='_';des=2;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        set_led_on(0,1,0,1,0,1,0,0);//светодиод аварийн.,норма, запятая 2
                        count_register=2;
                        hex2dec(data_register*100);
                        f_m1=1;
                        }
                }
        if (mode==3)//время до уставки 1
                {
                set_led_on(0,0,1,1,0,0,0,0);//светодиод предупр.,норма, запятая 2
                set_led_off(0,0,0,1,0,0,0,0);//светодиод норма
                if ((((sys_time-start_time_mode)<read_reg(19)*2000))&&(f_m1==0))//пока время индикации наименования
                        {
                        tis=3;sot='_';des=1;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        count_register=3;
                        hex2dec(data_register);
                        f_m1=1;
                        }
                }
        if (mode==4)//время до уставки 2
                {
                set_led_on(0,1,0,1,0,0,0,0);//светодиод аварийн.,норма, запятая 2
                set_led_off(0,0,0,1,0,0,0,0);//светодиод норма
                if ((((sys_time-start_time_mode)<read_reg(19)*2000))&&(f_m1==0))//пока время индикации наименования
                        {
                        tis=3;sot='_';des=2;ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        count_register=4;
                        hex2dec(data_register);
                        f_m1=1;
                        }
                }
        if (mode==5)//режим маскирование
                {
                set_led_on(0,1,1,1,0,0,0,0);//светодиод аварийн.,предупр.,норма
                set_led_off(0,0,0,1,0,0,0,0);//светодиод норма
                if ((((sys_time-start_time_mode)<read_reg(19)*2000))&&(f_m1==0))//пока время индикации наименования
                        {
                        tis=6;sot='_';des='_';ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        count_register=5;
                        hex2dec(data_register);
                        f_m1=1;
                        }
                }

        if (mode==6)//режим маскирование
                {
                set_led_on(0,1,1,1,0,0,0,0);//светодиод аварийн.,предупр.,норма
                set_led_off(0,0,0,1,0,0,0,0);//светодиод норма
                if ((((sys_time-start_time_mode)<read_reg(19)*2000))&&(f_m1==0))//пока время индикации наименования
                        {
                        tis='c';sot='_';des='_';ed=' ';
                        set_digit_off(' ',' ',' ',' ');
                        }
                else
                        {
                        count_register=6;
                        hex2dec(data_register);
                        f_m1=1;
                        }
                }
//----------------------------------------------------------
        if (mode==10)
                {
                if (count_register<7) count_register=7;
                hex2dec(count_register-6);
                if (des==0) des='_';
                tis='a';sot='_';
                set_digit_off(' ',' ',' ',' ');
                set_led_on(0,0,1,1,0,0,0,0);
                set_led_off(0,0,0,1,0,0,0,0);
                }

        if (mode==11)
                {
                if ((count_register==14)||(count_register==13)||(count_register==14)||(count_register==21)||(count_register==22))
                        {
                        hex2dec(data_register*100);
                        set_led_on(0,0,1,1,0,1,0,0);
                        set_led_off(0,0,0,1,0,1,0,0);
                        }
                else 
                        {
                        hex2dec(data_register);
                        set_led_on(0,0,1,1,0,0,0,0);
                        set_led_off(0,0,0,1,0,0,0,0);
                        }
                }
        
        
        if (key_plus_press==1)
                {
                start_time_mode=sys_time;
                if (count_key==0){if (mode==10)if (++count_register>MAX_REGISTER)count_register=MAX_REGISTER;}
                if ((count_key==0)||(count_key==21)||(count_key1==102))
                        {
                        if ((mode==11)||(mode==3)||(mode==4)||(mode==5)||(mode==6))
                                {
                                if ((count_register==13)||(count_register==14)||(count_register==21)||(count_register==22))data_register=data_register+0.01;
                                else data_register=data_register+1;
                                if (data_register>MAX_MIN[count_register,1])data_register=MAX_MIN[count_register,1];
                                }
                        if ((mode==1)||(mode==2))
                                {
                                data_register=data_register+0.01;
                                if (data_register>MAX_MIN[count_register,1])data_register=MAX_MIN[count_register,1];
                                }
                        if (count_key==0)count_key=60;if (count_key==21)count_key=20;
                        }
                rekey();
                }
        else if ((mode!=100)&&(key_enter_press==0)&&(key_mines_press==0)){count_key=0;count_key1=0;count_key2=0;}

        if (key_mines_press==1)
                {
                start_time_mode=sys_time;
                if (count_key==0){if (mode==10)if (--count_register<7)count_register=7;}
                if ((count_key==0)||(count_key==21)||(count_key1==102))
                        {
                        if ((mode==11)||(mode==3)||(mode==4)||(mode==5)||(mode==6))
                             {
                             if ((count_register==13)||(count_register==14)||(count_register==21)||(count_register==22))data_register=data_register-0.01;
                             else data_register=data_register-1;
                             if (data_register<MAX_MIN[count_register,0])data_register=MAX_MIN[count_register,0];
                             }
                        if ((mode==1)||(mode==2))
                                {
                                data_register=data_register-0.01;
                                if (data_register<MAX_MIN[count_register,0])data_register=MAX_MIN[count_register,0];
                                }
                        if (count_key==0)count_key=60;if (count_key==21)count_key=20;
                        }
                rekey();
                }
        else if ((mode!=100)&&(key_enter_press==0)&&(key_plus_press==0)){count_key=0;count_key1=0;count_key2=0;}

        if ((key_enter_press_switch==1)&&(key_plus_press==0)&&(key_mines_press==0)&&(key_mode_press==0)&&(mode!=0)&&(mode!=10))
                {
                ee_float=&reg[count_register];
                *ee_float=data_register;
                start_time_mode=sys_time;
                if (count_register==21)
                        {
                        ee_float=&kal[0];
                        *ee_float=adc_filter;
                        }
                if (count_register==22)
                        {
                        ee_float=&kal[0];
                        k_f=*ee_float;
                        ee_float=&kal[1];
                        *ee_float=20/(adc_filter-k_f);
                        }
                if (count_register==30)
                        {
                        for (i=0;i<30;i++)
                                {
                                ee_float=&reg[i];
                                *ee_float=FAKTORY[i];
                                }
                        }
                set_digit_on(' ',3,'a','п');
                set_digit_off(' ',3,'a','п');
                set_led_on(0,0,0,1,0,0,0,0);
                set_led_off(0,0,0,1,0,0,0,0);
                delay_ms(3000);key_enter_press_switch=0;
                set_digit_off(' ',' ',' ',' ');
                start_time_mode=sys_time;start_time=sys_time;
                f_m1=0;
                }
        if ((key_mode_press_switch==1)&&(key_4==1))
                {
                key_mode_press_switch=0;f_m1=0;
                start_time_mode=sys_time;
                switch (mode)
                        {
                        case 0: mode=1;data_register=read_reg(1);break;
                        case 1: mode=2;data_register=read_reg(2);break;
                        case 2: mode=3;data_register=read_reg(3);break;
                        case 3: mode=4;data_register=read_reg(4);break;
                        case 4: mode=5;data_register=read_reg(5);break;
                        case 5: mode=6;data_register=read_reg(6);break;
                        case 6: mode=0;break;
                        case 10:mode=11;data_register=read_reg(count_register);break;
                        case 11:mode=10;break;
                        case 100:mode=100;break;
                        }
                }

        if (((sys_time-start_time)>250)) 
                {
                set_digit_on(tis,sot,des,ed);
                if (((mode>0)&&(mode<7))||(mode==11))
                        {
                        if((key_plus_press==1)||(key_mines_press==1)) set_digit_off(tis,sot,des,ed);
                        else set_digit_off(' ',' ',' ',' ');
                        }
                if (mode==0)
                        {
                        set_digit_off(tis,sot,des,ed);
                        set_led_on(0,0,0,1,0,1,0,0);
                        set_led_off(0,0,0,1,0,1,0,0);
                        }
                start_time=sys_time;
                }
        };
}
Exemple #17
0
/**
* Add some entropy to the underlying PRNG
*/
void ANSI_X931_RNG::add_entropy(const byte input[], u32bit length)
   {
   prng->add_entropy(input, length);
   rekey();
   }
Exemple #18
0
/* process the characters one by one */
static int
process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
{
	char string[1024];
	pid_t pid;
	int bytes = 0;
	u_int i;
	u_char ch;
	char *s;

	for (i = 0; i < len; i++) {
		/* Get one character at a time. */
		ch = buf[i];

		if (escape_pending) {
			/* We have previously seen an escape character. */
			/* Clear the flag now. */
			escape_pending = 0;

			/* Process the escaped character. */
			switch (ch) {
			case '.':
				/* Terminate the connection. */
				snprintf(string, sizeof string, "%c.\r\n", escape_char);
				buffer_append(berr, string, strlen(string));

				quit_pending = 1;
				return -1;

			case 'Z' - 64:
				/* Suspend the program. */
				/* Print a message to that effect to the user. */
				snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
				buffer_append(berr, string, strlen(string));

				/* Restore terminal modes and suspend. */
				client_suspend_self(bin, bout, berr);

				/* We have been continued. */
				continue;

			case 'B':
				if (compat20) {
					snprintf(string, sizeof string,
					    "%cB\r\n", escape_char);
					buffer_append(berr, string,
					    strlen(string));
					channel_request_start(session_ident,
					    "break", 0);
					packet_put_int(1000);
					packet_send();
				}
				continue;

			case 'R':
				if (compat20) {
					if (datafellows & SSH_BUG_NOREKEY)
						logit("Server does not support re-keying");
					else
						need_rekeying = 1;
				}
				continue;

			case '&':
				/*
				 * Detach the program (continue to serve connections,
				 * but put in background and no more new connections).
				 */
				/* Restore tty modes. */
				leave_raw_mode();

				/* Stop listening for new connections. */
				channel_stop_listening();

				snprintf(string, sizeof string,
				    "%c& [backgrounded]\n", escape_char);
				buffer_append(berr, string, strlen(string));

				/* Fork into background. */
				pid = fork();
				if (pid < 0) {
					error("fork: %.100s", strerror(errno));
					continue;
				}
				if (pid != 0) {	/* This is the parent. */
					/* The parent just exits. */
					exit(0);
				}
				/* The child continues serving connections. */
				if (compat20) {
					buffer_append(bin, "\004", 1);
					/* fake EOF on stdin */
					return -1;
				} else if (!stdin_eof) {
					/*
					 * Sending SSH_CMSG_EOF alone does not always appear
					 * to be enough.  So we try to send an EOF character
					 * first.
					 */
					packet_start(SSH_CMSG_STDIN_DATA);
					packet_put_string("\004", 1);
					packet_send();
					/* Close stdin. */
					stdin_eof = 1;
					if (buffer_len(bin) == 0) {
						packet_start(SSH_CMSG_EOF);
						packet_send();
					}
				}
				continue;

			case '?':
				snprintf(string, sizeof string,
"%c?\r\n\
Supported escape sequences:\r\n\
%c.  - terminate connection\r\n\
%cB  - send a BREAK to the remote system\r\n\
%cC  - open a command line\r\n\
%cR  - Request rekey (SSH protocol 2 only)\r\n\
%c^Z - suspend ssh\r\n\
%c#  - list forwarded connections\r\n\
%c&  - background ssh (when waiting for connections to terminate)\r\n\
%c?  - this message\r\n\
%c%c  - send the escape character by typing it twice\r\n\
(Note that escapes are only recognized immediately after newline.)\r\n",
				    escape_char, escape_char, escape_char, escape_char,
				    escape_char, escape_char, escape_char, escape_char,
				    escape_char, escape_char, escape_char);
				buffer_append(berr, string, strlen(string));
				continue;

			case '#':
				snprintf(string, sizeof string, "%c#\r\n", escape_char);
				buffer_append(berr, string, strlen(string));
				s = channel_open_message();
				buffer_append(berr, s, strlen(s));
				xfree(s);
				continue;

			case 'C':
				process_cmdline();
				continue;

			default:
				if (ch != escape_char) {
					buffer_put_char(bin, escape_char);
					bytes++;
				}
				/* Escaped characters fall through here */
				break;
			}
		} else {
			/*
			 * The previous character was not an escape char. Check if this
			 * is an escape.
			 */
			if (last_was_cr && ch == escape_char) {
				/* It is. Set the flag and continue to next character. */
				escape_pending = 1;
				continue;
			}
		}

		/*
		 * Normal character.  Record whether it was a newline,
		 * and append it to the buffer.
		 */
		last_was_cr = (ch == '\r' || ch == '\n');
		buffer_put_char(bin, ch);
		bytes++;
	}
Exemple #19
0
void ANSI_X931_RNG::add_entropy(const byte input[], size_t length)
   {
   m_prng->add_entropy(input, length);
   rekey();
   }
Exemple #20
0
void ANSI_X931_RNG::reseed(size_t poll_bits)
   {
   m_prng->reseed(poll_bits);
   rekey();
   }
Exemple #21
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();
}
/**
 * \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;
}