Arduino Cryptography Library
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 }
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.
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.