├── README ├── sha256.cpp └── sha256.h /README: -------------------------------------------------------------------------------- 1 | This is a trimmed-down version of Peter Knight's excellent Cryptosuite library for Arduino, supporting secure hashing and hashed message authentication using SHA-256 and HMAC-SHA-256. 2 | 3 | To help fit complex applications within the limited code space of the Arduino, this version strips out the SHA-1 functionality -- it wasn't required for my OpenSesame code. 4 | 5 | https://github.com/Cathedrow/Cryptosuite 6 | 7 | The original also contains a test suite and further exposition on the use of hash functions. 8 | 9 | Installation: 10 | Make a 'libraries' directory with your Arduino folder if you do not already have one. 11 | Rename this folder 'Sha' and move it into that directory. 12 | Restart Arduino IDE to rescan for new libraries. 13 | -------------------------------------------------------------------------------- /sha256.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "sha256.h" 7 | 8 | const uint32_t SHA256_K[] PROGMEM = { 9 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 10 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 11 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 12 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 13 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 14 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 15 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 16 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 17 | }; 18 | 19 | const uint8_t SHA256_INIT_STATE[] PROGMEM = { 20 | 0x67,0xe6,0x09,0x6a, // H0 21 | 0x85,0xae,0x67,0xbb, // H1 22 | 0x72,0xf3,0x6e,0x3c, // H2 23 | 0x3a,0xf5,0x4f,0xa5, // H3 24 | 0x7f,0x52,0x0e,0x51, // H4 25 | 0x8c,0x68,0x05,0x9b, // H5 26 | 0xab,0xd9,0x83,0x1f, // H6 27 | 0x19,0xcd,0xe0,0x5b // H7 28 | }; 29 | 30 | #define ror32(num, bits) ((num << (32 - bits)) | (num >> bits)) 31 | 32 | void Sha256::init(void) { 33 | memcpy_P(state.b, SHA256_INIT_STATE, 32); 34 | byteCount = 0; 35 | bufferOffset = 0; 36 | } 37 | 38 | void Sha256::hashBlock() { 39 | uint8_t i; 40 | uint32_t a,b,c,d,e,f,g,h,t1,t2; 41 | 42 | a=state.w[0]; 43 | b=state.w[1]; 44 | c=state.w[2]; 45 | d=state.w[3]; 46 | e=state.w[4]; 47 | f=state.w[5]; 48 | g=state.w[6]; 49 | h=state.w[7]; 50 | 51 | for (i=0; i<64; i++) { 52 | if (i>=16) { 53 | t1 = buffer.w[i&15] + buffer.w[(i-7)&15]; 54 | t2 = buffer.w[(i-2)&15]; 55 | t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10); 56 | t2 = buffer.w[(i-15)&15]; 57 | t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3); 58 | buffer.w[i&15] = t1; 59 | } 60 | t1 = h; 61 | t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e) 62 | t1 += g ^ (e & (g ^ f)); // Ch(e,f,g) 63 | t1 += pgm_read_dword(SHA256_K + i); // Ki 64 | t1 += buffer.w[i&15]; // Wi 65 | t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a) 66 | t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c) 67 | h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; 68 | } 69 | state.w[0] += a; 70 | state.w[1] += b; 71 | state.w[2] += c; 72 | state.w[3] += d; 73 | state.w[4] += e; 74 | state.w[5] += f; 75 | state.w[6] += g; 76 | state.w[7] += h; 77 | } 78 | 79 | void Sha256::push(uint8_t data) { 80 | buffer.b[bufferOffset ^ 3] = data; 81 | bufferOffset++; 82 | if (bufferOffset == BLOCK_LENGTH) { 83 | hashBlock(); 84 | bufferOffset = 0; 85 | } 86 | } 87 | 88 | #if defined(ARDUINO) && ARDUINO >= 100 89 | size_t Sha256::write(uint8_t data) { 90 | #else 91 | void Sha256::write(uint8_t data) { 92 | #endif 93 | ++byteCount; 94 | push(data); 95 | #if defined(ARDUINO) && ARDUINO >= 100 96 | return 1; 97 | #endif 98 | } 99 | 100 | void Sha256::padBlock() { 101 | // Implement SHA-256 padding (fips180-2 §5.1.1) 102 | 103 | // Pad with 0x80 followed by 0x00 until the end of the block 104 | push(0x80); 105 | while (bufferOffset != 56) push(0x00); 106 | 107 | // Append length in the last 8 bytes. We're only using 32 bit lengths, but 108 | // SHA-2 supports 64 bit lengths so zero pad the top bits 109 | push(0); 110 | push(0); 111 | push(0); 112 | push(byteCount >> 29); 113 | push(byteCount >> 21); 114 | push(byteCount >> 13); 115 | push(byteCount >> 5); 116 | push(byteCount << 3); 117 | } 118 | 119 | uint8_t* Sha256::result(void) { 120 | // Pad to complete the last block 121 | padBlock(); 122 | 123 | // Swap byte order back 124 | for (uint8_t i = 0; i < 8; i++) { 125 | uint32_t a,b; 126 | a=state.w[i]; 127 | b=a<<24; 128 | b|=(a<<8) & 0x00ff0000; 129 | b|=(a>>8) & 0x0000ff00; 130 | b|=a>>24; 131 | state.w[i]=b; 132 | } 133 | 134 | // Return pointer to hash 135 | return state.b; 136 | } 137 | 138 | #define HMAC_IPAD 0x36 139 | #define HMAC_OPAD 0x5c 140 | 141 | void Sha256::initHmac(const uint8_t *key, size_t keyLength) { 142 | memset(keyBuffer, 0, BLOCK_LENGTH); 143 | if (keyLength > BLOCK_LENGTH) { 144 | // Hash long keys 145 | init(); 146 | for (;keyLength--;) write(*key++); 147 | memcpy(keyBuffer, result(), HASH_LENGTH); 148 | } else { 149 | // Block length keys are used as is 150 | memcpy(keyBuffer, key, keyLength); 151 | } 152 | reset(); 153 | } 154 | 155 | void Sha256::initHmac_EEPROM(const uint8_t *key, size_t keyLength) { 156 | memset(keyBuffer, 0, BLOCK_LENGTH); 157 | if (keyLength > BLOCK_LENGTH) { 158 | // Hash long keys 159 | init(); 160 | for (;keyLength--;) write(eeprom_read_byte(key++)); 161 | memcpy(keyBuffer, result(), HASH_LENGTH); 162 | } else { 163 | // Block length keys are used as is 164 | eeprom_read_block(keyBuffer, key, keyLength); 165 | } 166 | reset(); 167 | } 168 | 169 | uint8_t* Sha256::resultHmac(void) { 170 | uint8_t i; 171 | // Complete inner hash 172 | memcpy(innerHash, result(), HASH_LENGTH); 173 | // Calculate outer hash 174 | init(); 175 | for (i = 0; i < BLOCK_LENGTH; i++) write(keyBuffer[i] ^ HMAC_OPAD); 176 | for (i = 0; i < HASH_LENGTH; i++) write(innerHash[i]); 177 | return result(); 178 | } 179 | 180 | void Sha256::reset(void) { 181 | // Start inner hash 182 | init(); 183 | for (uint8_t i = 0; i < BLOCK_LENGTH; i++) { 184 | write(keyBuffer[i] ^ HMAC_IPAD); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /sha256.h: -------------------------------------------------------------------------------- 1 | #ifndef Sha256_h 2 | #define Sha256_h 3 | 4 | #include 5 | #include "Print.h" 6 | 7 | #define HASH_LENGTH 32 8 | #define BLOCK_LENGTH 64 9 | 10 | class Sha256 : public Print { 11 | 12 | union Buffer { 13 | uint8_t b[BLOCK_LENGTH]; 14 | uint32_t w[BLOCK_LENGTH / 4]; 15 | }; 16 | 17 | union State { 18 | uint8_t b[HASH_LENGTH]; 19 | uint32_t w[HASH_LENGTH / 4]; 20 | }; 21 | 22 | public: 23 | void init(void); 24 | void initHmac(const uint8_t *key, size_t keyLength); 25 | void initHmac_EEPROM(const uint8_t *key, size_t keyLength); 26 | 27 | // Reset to initial state, but preserve key material. 28 | void reset(void); 29 | 30 | uint8_t* result(void); 31 | uint8_t* resultHmac(void); 32 | #if defined(ARDUINO) && ARDUINO >= 100 33 | virtual size_t write(uint8_t); 34 | #else 35 | virtual void write(uint8_t); 36 | #endif 37 | using Print::write; 38 | 39 | private: 40 | void hashBlock(); 41 | void padBlock(); 42 | void push(uint8_t data); 43 | 44 | uint32_t byteCount; 45 | 46 | uint8_t keyBuffer[BLOCK_LENGTH]; 47 | uint8_t innerHash[HASH_LENGTH]; 48 | 49 | State state; 50 | Buffer buffer; 51 | uint8_t bufferOffset; 52 | }; 53 | 54 | #endif 55 | --------------------------------------------------------------------------------