HMAC256 Library is needed

I tried to use Cryptosuit but I went through errors that I could not know how to fix and why they occur? I am using Arduino IDE 1.6.7 installed in Windows 10 and the controller is ATMEG 328. The previous issue posted here:
https://forum.arduino.cc/index.php?topic=372312.0

Please help me with links to "working" HMAC256 libraries.

Not working is a broad error.
you just say you have a problem but do not tell what,
so that is the same as when I would say I happens because.

So can you please more specific what errors you get?
Did you google for the specific error messages?
What did you get?
Have you tried an older version of the IDE?

itroublee:
I tried to use Cryptosuit but I went through errors that I could not know how to fix and why they occur?

Why the compile errors occur is always explained in the detailed error message.

There you can read something like "wrong return type" or which might cause the error. If you are using a newer version of the compiler than was used while developing the library 6 years ago, you might have to do some small changes to make the code compatible with newer compiler versions.

About one year ago I tested the library and example sketch after this thread showed up in this forum:
http://forum.arduino.cc/index.php?topic=300488.0

Library and example sketch compiled fine when I tested it.

If you are not bound to IDE IDE 1.6.7, perhaps just use an older version of the IDE!

@robtillaart: the post contains a link for the detailed problem. some one have proposed some changes to the library but I do not feel comfortable to do changes as crypto is very tricky and small changes can result in unexpected problems.

@jurs: you said you tested it previously. Can you remember what version of IDE so I download it.

itroublee:
@jurs: you said you tested it previously. Can you remember what version of IDE so I download it.

This code compiles fine with Arduino 1.0.5-r2 and the library I used in February 2015:

#include "sha256.h"

uint8_t hmacKey1[]={
  0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b
};
uint8_t hmacKey2[]={
  0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,
  0x15,0x16,0x17,0x18,0x19
};
uint8_t hmacKey3[]={
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
};
uint8_t hmacKey4[]={
  0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c
};
uint8_t hmacKey5[]={
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
};

void printHash(uint8_t* hash) {
  int i;
  for (i=0; i<32; i++) {
    Serial.print("0123456789abcdef"[hash[i]>>4]);
    Serial.print("0123456789abcdef"[hash[i]&0xf]);
  }
  Serial.println();
}

void setup() {
  uint8_t* hash;
  uint32_t a;
  
  Serial.begin(9600);

  // SHA tests
  Serial.println("Test: FIPS 180-2 B.1");
  Serial.println("Expect:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
  Serial.print("Result:");
  Sha256.init();
  Sha256.print("abc");
  printHash(Sha256.result());
  Serial.println();

  Serial.println("Test: FIPS 180-2 B.2");
  Serial.println("Expect:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
  Serial.print("Result:");
  Sha256.init();
  Sha256.print("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
  printHash(Sha256.result());
  Serial.println();

  // HMAC tests
  Serial.println("Test: RFC4231 4.2");
  Serial.println("Expect:b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
  Serial.print("Result:");
  Sha256.initHmac(hmacKey1,20);
  Sha256.print("Hi There");
  printHash(Sha256.resultHmac());
  Serial.println();
  
  Serial.println("Test: RFC4231 4.3");
  Serial.println("Expect:5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843");
  Serial.print("Result:");
  Sha256.initHmac((uint8_t*)"Jefe",4);
  Sha256.print("what do ya want for nothing?");
  printHash(Sha256.resultHmac());
  Serial.println();
  
  Serial.println("Test: RFC4231 4.4");
  Serial.println("Expect:773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe");
  Serial.print("Result:");
  Sha256.initHmac(hmacKey3,20);
  for (a=0; a<50; a++) Sha256.write(0xdd);
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.5");
  Serial.println("Expect:82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b");
  Serial.print("Result:");
  Sha256.initHmac(hmacKey2,25);
  for (a=0; a<50; a++) Sha256.write(0xcd);
  printHash(Sha256.resultHmac());
  Serial.println();
  
  Serial.println("Test: RFC4231 4.6");
  Serial.println("Expect:a3b6167473100ee06e0c796c2955552b-------------------------------");
  Serial.print("Result:");
  Sha256.initHmac(hmacKey4,20);
  Sha256.print("Test With Truncation");
  printHash(Sha256.resultHmac());
  Serial.println();
  
  Serial.println("Test: RFC4231 4.7");
  Serial.println("Expect:60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54");
  Serial.print("Result:");
  Sha256.initHmac(hmacKey5,131);
  Sha256.print("Test Using Larger Than Block-Size Key - Hash Key First");
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.8");
  Serial.println("Expect:9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2");
  Serial.print("Result:");
  Sha256.initHmac(hmacKey5,131);
  Sha256.print("This is a test using a larger than block-size key and a larger than "
  "block-size data. The key needs to be hashed before being used by the HMAC algorithm.");
  printHash(Sha256.resultHmac());
  Serial.println();
  
  // Long tests 
  Serial.println("Test: FIPS 180-2 B.3 (Processing 1000000 characters. This will take a while.)");
  Serial.println("Expect:cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
  Serial.print("Result:");
  Sha256.init();
  for (a=0; a<1000000; a++) Sha256.write('a');
  printHash(Sha256.result());
}

void loop() {
}

And the library I used in February 2015 was most likely exactly the same library which was linked to in the thread of February 2015.

That sketch does not only compile error-free, it also creates correct output as it seems:

Test: FIPS 180-2 B.1
Expect:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Result:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

Test: FIPS 180-2 B.2
Expect:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1
Result:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1

Test: RFC4231 4.2
Expect:b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
Result:b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7

Test: RFC4231 4.3
Expect:5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
Result:5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843

Test: RFC4231 4.4
Expect:773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe
Result:773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe

Test: RFC4231 4.5
Expect:82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b
Result:82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b

Test: RFC4231 4.6
Expect:a3b6167473100ee06e0c796c2955552b-------------------------------
Result:a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5

Test: RFC4231 4.7
Expect:60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54
Result:60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54

Test: RFC4231 4.8
Expect:9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2
Result:9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2

Test: FIPS 180-2 B.3 (Processing 1000000 characters. This will take a while.)
Expect:cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0
Result:cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0

Last output processing 1000000 characters needs a very long time, though.

After modifying jurs' code (posted above) to solve low-on-memory, those are the results using 'my' modified library.

Test: FIPS 180-2 B.1
Expect:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Result:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

Test: FIPS 180-2 B.2
Expect:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1
Result:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1

Test: RFC4231 4.2
Expect:b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
Result:b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7

Test: RFC4231 4.3
Expect:5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
Result:5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843

Test: RFC4231 4.4
Expect:773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe
Result:773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe

Test: RFC4231 4.5
Expect:82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b
Result:82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b

Test: RFC4231 4.6
Expect:a3b6167473100ee06e0c796c2955552b-------------------------------
Result:a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5

Test: RFC4231 4.7
Expect:60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54
Result:60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54

Test: RFC4231 4.8
Expect:9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2
Result:9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2

Test: FIPS 180-2 B.3 (Processing 1000000 characters. This will take a while.)
Expect:cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0
Result:cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0

I'm now 100% confident that the proposed changes are harmless and would use the modified library. The change from return type void to size_t is harmless anyway as the return result was not used; as stated in the other thread, maybe the function should return 1 but the C/CPP compiler does not complain if nothing is returned. My only doubt was the PROGMEM arrays as I was not sure of the implications of adding the const keyword.

Code to follow

Modified version of jurs' code; just used the F macro in some places

#include "sha256.h"

uint8_t hmacKey1[] = {
  0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
};
uint8_t hmacKey2[] = {
  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
  0x15, 0x16, 0x17, 0x18, 0x19
};
uint8_t hmacKey3[] = {
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
};
uint8_t hmacKey4[] = {
  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
};
uint8_t hmacKey5[] = {
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
};

void printHash(uint8_t* hash) {
  int i;
  for (i = 0; i < 32; i++) {
    Serial.print("0123456789abcdef"[hash[i] >> 4]);
    Serial.print("0123456789abcdef"[hash[i] & 0xf]);
  }
  Serial.println();
}

void setup() {
  uint8_t* hash;
  uint32_t a;

  Serial.begin(9600);

  // SHA tests
  Serial.println("Test: FIPS 180-2 B.1");
  Serial.println(F("Expect:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
  Serial.print("Result:");
  Sha256.init();
  Sha256.print("abc");
  printHash(Sha256.result());
  Serial.println();

  Serial.println("Test: FIPS 180-2 B.2");
  Serial.println(F("Expect:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"));
  Serial.print("Result:");
  Sha256.init();
  Sha256.print(F("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
  printHash(Sha256.result());
  Serial.println();

  // HMAC tests
  Serial.println("Test: RFC4231 4.2");
  Serial.println(F("Expect:b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"));
  Serial.print("Result:");
  Sha256.initHmac(hmacKey1, 20);
  Sha256.print("Hi There");
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.3");
  Serial.println(F("Expect:5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"));
  Serial.print("Result:");
  Sha256.initHmac((uint8_t*)"Jefe", 4);
  Sha256.print("what do ya want for nothing?");
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.4");
  Serial.println(F("Expect:773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"));
  Serial.print("Result:");
  Sha256.initHmac(hmacKey3, 20);
  for (a = 0; a < 50; a++) Sha256.write(0xdd);
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.5");
  Serial.println(F("Expect:82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"));
  Serial.print("Result:");
  Sha256.initHmac(hmacKey2, 25);
  for (a = 0; a < 50; a++) Sha256.write(0xcd);
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.6");
  Serial.println(F("Expect:a3b6167473100ee06e0c796c2955552b-------------------------------"));
  Serial.print("Result:");
  Sha256.initHmac(hmacKey4, 20);
  Sha256.print("Test With Truncation");
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.7");
  Serial.println(F("Expect:60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"));
  Serial.print("Result:");
  Sha256.initHmac(hmacKey5, 131);
  Sha256.print("Test Using Larger Than Block-Size Key - Hash Key First");
  printHash(Sha256.resultHmac());
  Serial.println();

  Serial.println("Test: RFC4231 4.8");
  Serial.println(F("Expect:9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"));
  Serial.print("Result:");
  Sha256.initHmac(hmacKey5, 131);
  Sha256.print("This is a test using a larger than block-size key and a larger than "
               "block-size data. The key needs to be hashed before being used by the HMAC algorithm.");
  printHash(Sha256.resultHmac());
  Serial.println();

  // Long tests
  Serial.println("Test: FIPS 180-2 B.3 (Processing 1000000 characters. This will take a while.)");
  Serial.println(F("Expect:cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"));
  Serial.print("Result:");
  Sha256.init();
  for (a = 0; a < 1000000; a++) Sha256.write('a');
  printHash(Sha256.result());
}

void loop() {
}

Modified sha256.h

#ifndef Sha256_h
#define Sha256_h

#include <inttypes.h>
#include "Print.h"

#define HASH_LENGTH 32
#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 Sha256Class : public Print
{
  public:
    void init(void);
    void initHmac(const uint8_t* secret, int secretLength);
    uint8_t* result(void);
    uint8_t* resultHmac(void);
    // 20160116; changed void to size_t
    virtual size_t write(uint8_t);
    using Print::write;
  private:
    void pad();
    void addUncounted(uint8_t data);
    void hashBlock();
    uint32_t ror32(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 Sha256Class Sha256;

#endif

Modified sha256.cpp

#include <string.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "sha256.h"

// 20160116; added const
const uint32_t sha256K[] PROGMEM = {
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

#define BUFFER_SIZE 64

// 20160116; added const
const uint8_t sha256InitState[] PROGMEM = {
  0x67, 0xe6, 0x09, 0x6a, // H0
  0x85, 0xae, 0x67, 0xbb, // H1
  0x72, 0xf3, 0x6e, 0x3c, // H2
  0x3a, 0xf5, 0x4f, 0xa5, // H3
  0x7f, 0x52, 0x0e, 0x51, // H4
  0x8c, 0x68, 0x05, 0x9b, // H5
  0xab, 0xd9, 0x83, 0x1f, // H6
  0x19, 0xcd, 0xe0, 0x5b // H7
};

void Sha256Class::init(void) {
  memcpy_P(state.b, sha256InitState, 32);
  byteCount = 0;
  bufferOffset = 0;
}

uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits) {
  return ((number << (32 - bits)) | (number >> bits));
}

void Sha256Class::hashBlock() {
  uint8_t i;
  uint32_t a, b, c, d, e, f, g, h, t1, t2;

  a = state.w[0];
  b = state.w[1];
  c = state.w[2];
  d = state.w[3];
  e = state.w[4];
  f = state.w[5];
  g = state.w[6];
  h = state.w[7];

  for (i = 0; i < 64; i++) {
    if (i >= 16) {
      t1 = buffer.w[i & 15] + buffer.w[(i - 7) & 15];
      t2 = buffer.w[(i - 2) & 15];
      t1 += ror32(t2, 17) ^ ror32(t2, 19) ^ (t2 >> 10);
      t2 = buffer.w[(i - 15) & 15];
      t1 += ror32(t2, 7) ^ ror32(t2, 18) ^ (t2 >> 3);
      buffer.w[i & 15] = t1;
    }
    t1 = h;
    t1 += ror32(e, 6) ^ ror32(e, 11) ^ ror32(e, 25); // ∑1(e)
    t1 += g ^ (e & (g ^ f)); // Ch(e,f,g)
    t1 += pgm_read_dword(sha256K + i); // Ki
    t1 += buffer.w[i & 15]; // Wi
    t2 = ror32(a, 2) ^ ror32(a, 13) ^ ror32(a, 22); // ∑0(a)
    t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c)
    h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
  }
  state.w[0] += a;
  state.w[1] += b;
  state.w[2] += c;
  state.w[3] += d;
  state.w[4] += e;
  state.w[5] += f;
  state.w[6] += g;
  state.w[7] += h;
}

void Sha256Class::addUncounted(uint8_t data) {
  buffer.b[bufferOffset ^ 3] = data;
  bufferOffset++;
  if (bufferOffset == BUFFER_SIZE) {
    hashBlock();
    bufferOffset = 0;
  }
}

// 20160116; changed void to size_t
size_t Sha256Class::write(uint8_t data) {
  ++byteCount;
  addUncounted(data);
}

void Sha256Class::pad() {
  // Implement SHA-256 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* Sha256Class::result(void) {
  // Pad to complete the last block
  pad();

  // Swap byte order back
  for (int i = 0; i < 8; 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

uint8_t keyBuffer[BLOCK_LENGTH]; // K0 in FIPS-198a
uint8_t innerHash[HASH_LENGTH];

void Sha256Class::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* Sha256Class::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();
}
Sha256Class Sha256;

@sterretje
Thanks for sharing, good job,

one small remark wrt print inheritance, write should return 1.

size_t Sha256Class::write(uint8_t data) {
 ++byteCount;
 addUncounted(data);
 return 1;
}

Noticed that the truncating test 4.6 does not work? (no time to dive into)