-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
dentellaluca
committed
Jan 16, 2016
1 parent
8adae40
commit c44cce0
Showing
3 changed files
with
204 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
name=TOTP library | ||
version=1.0.0 | ||
version=1.0.1 | ||
author=Luca Dentella <[email protected]> | ||
maintainer=Luca Dentella <[email protected]> | ||
sentence=Library to generate Time-based One-Time Passwords | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
#include <string.h> | ||
#include <avr/io.h> | ||
#include <avr/pgmspace.h> | ||
#include "sha1.h" | ||
|
||
#define SHA1_K0 0x5a827999 | ||
#define SHA1_K20 0x6ed9eba1 | ||
#define SHA1_K40 0x8f1bbcdc | ||
#define SHA1_K60 0xca62c1d6 | ||
|
||
const uint8_t sha1InitState[] PROGMEM = { | ||
0x01,0x23,0x45,0x67, // H0 | ||
0x89,0xab,0xcd,0xef, // H1 | ||
0xfe,0xdc,0xba,0x98, // H2 | ||
0x76,0x54,0x32,0x10, // H3 | ||
0xf0,0xe1,0xd2,0xc3 // H4 | ||
}; | ||
|
||
void Sha1Class::init(void) { | ||
memcpy_P(state.b,sha1InitState,HASH_LENGTH); | ||
byteCount = 0; | ||
bufferOffset = 0; | ||
} | ||
|
||
uint32_t Sha1Class::rol32(uint32_t number, uint8_t bits) { | ||
return ((number << bits) | (number >> (32-bits))); | ||
} | ||
|
||
void Sha1Class::hashBlock() { | ||
uint8_t i; | ||
uint32_t a,b,c,d,e,t; | ||
|
||
a=state.w[0]; | ||
b=state.w[1]; | ||
c=state.w[2]; | ||
d=state.w[3]; | ||
e=state.w[4]; | ||
for (i=0; i<80; i++) { | ||
if (i>=16) { | ||
t = buffer.w[(i+13)&15] ^ buffer.w[(i+8)&15] ^ buffer.w[(i+2)&15] ^ buffer.w[i&15]; | ||
buffer.w[i&15] = rol32(t,1); | ||
} | ||
if (i<20) { | ||
t = (d ^ (b & (c ^ d))) + SHA1_K0; | ||
} else if (i<40) { | ||
t = (b ^ c ^ d) + SHA1_K20; | ||
} else if (i<60) { | ||
t = ((b & c) | (d & (b | c))) + SHA1_K40; | ||
} else { | ||
t = (b ^ c ^ d) + SHA1_K60; | ||
} | ||
t+=rol32(a,5) + e + buffer.w[i&15]; | ||
e=d; | ||
d=c; | ||
c=rol32(b,30); | ||
b=a; | ||
a=t; | ||
} | ||
state.w[0] += a; | ||
state.w[1] += b; | ||
state.w[2] += c; | ||
state.w[3] += d; | ||
state.w[4] += e; | ||
} | ||
|
||
void Sha1Class::addUncounted(uint8_t data) { | ||
buffer.b[bufferOffset ^ 3] = data; | ||
bufferOffset++; | ||
if (bufferOffset == BLOCK_LENGTH) { | ||
hashBlock(); | ||
bufferOffset = 0; | ||
} | ||
} | ||
|
||
__WRITE_RESULT Sha1Class::write(uint8_t data) { | ||
++byteCount; | ||
addUncounted(data); | ||
|
||
__WRITE_RETURN(1); | ||
} | ||
|
||
void Sha1Class::pad() { | ||
// Implement SHA-1 padding (fips180-2 §5.1.1) | ||
|
||
// Pad with 0x80 followed by 0x00 until the end of the block | ||
addUncounted(0x80); | ||
while (bufferOffset != 56) addUncounted(0x00); | ||
|
||
// Append length in the last 8 bytes | ||
addUncounted(0); // We're only using 32 bit lengths | ||
addUncounted(0); // But SHA-1 supports 64 bit lengths | ||
addUncounted(0); // So zero pad the top bits | ||
addUncounted(byteCount >> 29); // Shifting to multiply by 8 | ||
addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as | ||
addUncounted(byteCount >> 13); // byte. | ||
addUncounted(byteCount >> 5); | ||
addUncounted(byteCount << 3); | ||
} | ||
|
||
|
||
uint8_t* Sha1Class::result(void) { | ||
// Pad to complete the last block | ||
pad(); | ||
|
||
// Swap byte order back | ||
for (int i=0; i<5; i++) { | ||
uint32_t a,b; | ||
a=state.w[i]; | ||
b=a<<24; | ||
b|=(a<<8) & 0x00ff0000; | ||
b|=(a>>8) & 0x0000ff00; | ||
b|=a>>24; | ||
state.w[i]=b; | ||
} | ||
|
||
// Return pointer to hash (20 characters) | ||
return state.b; | ||
} | ||
|
||
#define HMAC_IPAD 0x36 | ||
#define HMAC_OPAD 0x5c | ||
|
||
void Sha1Class::initHmac(const uint8_t* key, int keyLength) { | ||
uint8_t i; | ||
memset(keyBuffer,0,BLOCK_LENGTH); | ||
if (keyLength > BLOCK_LENGTH) { | ||
// Hash long keys | ||
init(); | ||
for (;keyLength--;) write(*key++); | ||
memcpy(keyBuffer,result(),HASH_LENGTH); | ||
} else { | ||
// Block length keys are used as is | ||
memcpy(keyBuffer,key,keyLength); | ||
} | ||
// Start inner hash | ||
init(); | ||
for (i=0; i<BLOCK_LENGTH; i++) { | ||
write(keyBuffer[i] ^ HMAC_IPAD); | ||
} | ||
} | ||
|
||
uint8_t* Sha1Class::resultHmac(void) { | ||
uint8_t i; | ||
// Complete inner hash | ||
memcpy(innerHash,result(),HASH_LENGTH); | ||
// Calculate outer hash | ||
init(); | ||
for (i=0; i<BLOCK_LENGTH; i++) write(keyBuffer[i] ^ HMAC_OPAD); | ||
for (i=0; i<HASH_LENGTH; i++) write(innerHash[i]); | ||
return result(); | ||
} | ||
Sha1Class Sha1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#ifndef Sha1_h | ||
#define Sha1_h | ||
|
||
#include <inttypes.h> | ||
#include "Print.h" | ||
|
||
#if ARDUINO < 100 | ||
#define __WRITE_RESULT void | ||
#define __WRITE_RETURN(x) return; | ||
#else | ||
#define __WRITE_RESULT size_t | ||
#define __WRITE_RETURN(x) return x; | ||
#endif | ||
|
||
#define HASH_LENGTH 20 | ||
#define BLOCK_LENGTH 64 | ||
|
||
union _buffer { | ||
uint8_t b[BLOCK_LENGTH]; | ||
uint32_t w[BLOCK_LENGTH/4]; | ||
}; | ||
union _state { | ||
uint8_t b[HASH_LENGTH]; | ||
uint32_t w[HASH_LENGTH/4]; | ||
}; | ||
|
||
class Sha1Class : public Print | ||
{ | ||
public: | ||
void init(void); | ||
void initHmac(const uint8_t* secret, int secretLength); | ||
uint8_t* result(void); | ||
uint8_t* resultHmac(void); | ||
virtual __WRITE_RESULT write(uint8_t); | ||
using Print::write; | ||
private: | ||
void pad(); | ||
void addUncounted(uint8_t data); | ||
void hashBlock(); | ||
uint32_t rol32(uint32_t number, uint8_t bits); | ||
_buffer buffer; | ||
uint8_t bufferOffset; | ||
_state state; | ||
uint32_t byteCount; | ||
uint8_t keyBuffer[BLOCK_LENGTH]; | ||
uint8_t innerHash[HASH_LENGTH]; | ||
|
||
}; | ||
extern Sha1Class Sha1; | ||
|
||
#endif |