Arduino Cryptography Library
 All Classes Files Functions Variables Enumerations Enumerator Pages
RingOscillatorNoiseSource.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "RingOscillatorNoiseSource.h"
24 #include "Crypto.h"
25 #include "RNG.h"
26 #include <Arduino.h>
27 
100 // Choose the input capture timer and pin to use for this board.
101 #if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
102 // Arduino Mega or Mega 2560 - input capture on TIMER4 and D49/PL0.
103 #define RING_TIMER 4
104 #define RING_PIN 49
105 #define RING_CAPT_vect TIMER4_CAPT_vect
106 #define RING_ICR ICR4
107 #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
108 // Arduino Leonardo - input capture on Timer1 and D4/PD4.
109 #define RING_TIMER 1
110 #define RING_PIN 4
111 #define RING_CAPT_vect TIMER1_CAPT_vect
112 #define RING_ICR ICR1
113 #else
114 // Assuming Arduino Uno or equivalent - input capture on TIMER1 and D8/PB0.
115 #define RING_TIMER 1
116 #define RING_PIN 8
117 #define RING_CAPT_vect TIMER1_CAPT_vect
118 #define RING_ICR ICR1
119 #endif
120 
121 // Calibration states.
122 #define NOISE_NOT_CALIBRATING 0
123 #define NOISE_CALIBRATING 1
124 
125 // If there is no capture event for this many milliseconds,
126 // then assume that the oscillator is stopped or disconnected.
127 #define RING_DISCONNECT_TIME 200
128 
129 RingOscillatorNoiseSource::RingOscillatorNoiseSource()
130  : calState(NOISE_CALIBRATING)
131  , lastSignal(millis())
132 {
133  // Initialize the bit collection routines.
134  restart();
135 
136  // Set up the capture pin as an input with no pull-ups.
137  pinMode(RING_PIN, INPUT);
138  digitalWrite(RING_PIN, LOW);
139 
140 #if RING_TIMER == 1
141  // Set up TIMER1 to perform input capture on PB8/D8.
142  TCCR1B = 0; // Turn off TIMER1.
143  TIMSK1 = 0; // Turn off TIMER1 interrupts.
144  TCNT1 = 0; // Zero the timer.
145  TCCR1A = 0; // Turn off output compare.
146  TCCR1B |= (1 << ICES1); // Input capture on rising edge.
147  TIMSK1 |= (1 << ICIE1); // Input capture interrupts enabled.
148 
149  // Start TIMER1 at the highest frequency with no prescaling.
150  TCCR1B |= (1 << CS10);
151 #elif RING_TIMER == 4
152  // Set up TIMER4 to perform input capture on PL0/D49.
153  TCCR4B = 0; // Turn off TIMER4.
154  TIMSK4 = 0; // Turn off TIMER4 interrupts.
155  TCNT4 = 0; // Zero the timer.
156  TCCR4A = 0; // Turn off output compare.
157  TCCR4B |= (1 << ICES4); // Input capture on rising edge.
158  TIMSK4 |= (1 << ICIE4); // Input capture interrupts enabled.
159 
160  // Start TIMER4 at the highest frequency with no prescaling.
161  TCCR4B |= (1 << CS10);
162 #endif
163 }
164 
165 RingOscillatorNoiseSource::~RingOscillatorNoiseSource()
166 {
167  // Turn off the capture timer.
168 #if RING_TIMER == 1
169  TCCR1B = 0;
170 #elif RING_TIMER == 4
171  TCCR4B = 0;
172 #endif
173 
174  // Clean up.
175  clean(buffer);
176 }
177 
179 {
180  return calState == NOISE_CALIBRATING;
181 }
182 
183 static uint16_t volatile out = 0;
184 static uint8_t volatile outBits = 0;
185 
186 // Interrupt service routine for the timer's input capture interrupt.
187 ISR(RING_CAPT_vect)
188 {
189  // We are interested in the jitter; that is the difference in
190  // time between one rising edge and the next in the signal.
191  // Extract a single bit from the jitter and add it to the
192  // rolling "out" buffer for the main code to process later.
193  // If the buffer overflows, we discard bits and keep going.
194  static uint16_t prev = 0;
195  uint16_t next = RING_ICR;
196  out = (out << 1) | ((next - prev) & 1);
197  prev = next;
198  ++outBits;
199 }
200 
202 {
203  // If the "out" buffer is full, then convert the bits. Turn off
204  // interrupts while we read the "out" buffer and reset "outBits".
205  unsigned long now = millis();
206  cli();
207  if (outBits >= 16) {
208  uint16_t bits = out;
209  outBits = 0;
210  sei();
211  for (uint8_t index = 0; index < 8; ++index) {
212  // Collect two bits of input and remove bias using the Von Neumann
213  // method. If both bits are the same, then discard both.
214  // Otherwise choose one of the bits and output that one.
215  // We have to do this carefully so that instruction timing does
216  // not reveal the value of the bit that is chosen.
217  if ((bits ^ (bits << 1)) & 0x8000) {
218  // The bits are different: add the top-most to the buffer.
219  if (posn < sizeof(buffer)) {
220  buffer[posn] = (buffer[posn] >> 1) |
221  (((uint8_t)(bits >> 8)) & (uint8_t)0x80);
222  if (++bitNum >= 8) {
223  ++posn;
224  bitNum = 0;
225  }
226  }
227  }
228  bits = bits << 2;
229  }
230  } else {
231  // The "out" buffer isn't full yet. Re-enable interrupts.
232  sei();
233 
234  // If it has been too long since the last useful block,
235  // then go back to calibrating. The oscillator may be
236  // stopped or disconnected.
237  if (calState == NOISE_NOT_CALIBRATING) {
238  if ((now - lastSignal) >= RING_DISCONNECT_TIME) {
239  restart();
240  calState = NOISE_CALIBRATING;
241  }
242  }
243  }
244 
245  // If the buffer is full, then stir it into the random number pool.
246  // We credit 1 bit of entropy for every 8 bits of output because
247  // ring oscillators aren't quite as good as a true noise source.
248  // We have to collect a lot more data to get something random enough.
249  if (posn >= sizeof(buffer)) {
250  output(buffer, posn, posn);
251  restart();
252  calState = NOISE_NOT_CALIBRATING;
253  lastSignal = now;
254  }
255 }
256 
257 void RingOscillatorNoiseSource::restart()
258 {
259  clean(buffer);
260  prevBit = 0;
261  posn = 0;
262  bitNum = 0;
263 }
void stir()
Stirs entropy from this noise source into the global random number pool.
bool calibrating() const
Determine if the noise source is still calibrating itself.
virtual void output(const uint8_t *data, size_t len, unsigned int credit)
Called from subclasses to output noise to the global random number pool.