diff --git a/.gitignore b/.gitignore index f1f80112..7aaa89c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ backup *.swp hardware +*.o +*.a +.depend diff --git a/host/Crypto/.gitignore b/host/Crypto/.gitignore new file mode 100644 index 00000000..1fc3ed4c --- /dev/null +++ b/host/Crypto/.gitignore @@ -0,0 +1 @@ +Test* diff --git a/host/Crypto/Makefile b/host/Crypto/Makefile new file mode 100644 index 00000000..bbffdf64 --- /dev/null +++ b/host/Crypto/Makefile @@ -0,0 +1,127 @@ + +.PHONY: all clean check + +TOPDIR = ../.. +SRCDIR = $(TOPDIR)/libraries/Crypto + +#VPATH = $(SRCDIR) +vpath %.cpp $(SRCDIR) +vpath %.o . +vpath %.ino $(SRCDIR)/examples +vpath %.sketch . + +LIBRARY = libCrypto.a + +CPPFLAGS = \ + -I$(TOPDIR)/host/emulation \ + -I$(TOPDIR)/libraries/Crypto \ + -DHOST_BUILD + +CXXFLAGS = -g -Wall $(CPPFLAGS) + +SOURCES = \ + AES128.cpp \ + AES192.cpp \ + AES256.cpp \ + AESCommon.cpp \ + AuthenticatedCipher.cpp \ + BigNumberUtil.cpp \ + BLAKE2b.cpp \ + BLAKE2s.cpp \ + BlockCipher.cpp \ + CBC.cpp \ + CFB.cpp \ + ChaCha.cpp \ + ChaChaPoly.cpp \ + Cipher.cpp \ + Crypto.cpp \ + CTR.cpp \ + Curve25519.cpp \ + EAX.cpp \ + Ed25519.cpp \ + GCM.cpp \ + GF128.cpp \ + GHASH.cpp \ + Hash.cpp \ + KeccakCore.cpp \ + NoiseSource.cpp \ + OFB.cpp \ + OMAC.cpp \ + Poly1305.cpp \ + RNG_host.cpp \ + SHA256.cpp \ + SHA3.cpp \ + SHA512.cpp \ + SHAKE.cpp \ + Speck.cpp \ + SpeckSmall.cpp \ + SpeckTiny.cpp \ + XOF.cpp \ + XTS.cpp + +SKETCHES = \ + TestAES/TestAES.ino \ + TestBigNumberUtil/TestBigNumberUtil.ino \ + TestBLAKE2b/TestBLAKE2b.ino \ + TestBLAKE2s/TestBLAKE2s.ino \ + TestCBC/TestCBC.ino \ + TestCFB/TestCFB.ino \ + TestChaCha/TestChaCha.ino \ + TestChaChaPoly/TestChaChaPoly.ino \ + TestCTR/TestCTR.ino \ + TestCurve25519/TestCurve25519.ino \ + TestCurve25519Math/TestCurve25519Math.ino \ + TestEAX/TestEAX.ino \ + TestEd25519/TestEd25519.ino \ + TestGCM/TestGCM.ino \ + TestGHASH/TestGHASH.ino \ + TestOFB/TestOFB.ino \ + TestPoly1305/TestPoly1305.ino \ + TestSHA256/TestSHA256.ino \ + TestSHA3_256/TestSHA3_256.ino \ + TestSHA3_512/TestSHA3_512.ino \ + TestSHA512/TestSHA512.ino \ + TestSHAKE128/TestSHAKE128.ino \ + TestSHAKE256/TestSHAKE256.ino \ + TestSpeck/TestSpeck.ino \ + TestXTS/TestXTS.ino \ + +OBJECTS = $(patsubst %.cpp,%.o,$(SOURCES)) +DEPS = $(patsubst %.cpp,.depend/%.d,$(SOURCES)) + +SKETCH_OUTPUTS = $(patsubst %.ino,%.sketch,$(SKETCHES)) + +all: $(LIBRARY) + +$(LIBRARY): $(OBJECTS) + $(RM) $(LIBRARY) + $(AR) cr $(LIBRARY) $(OBJECTS) + +clean: + $(RM) $(OBJECTS) $(LIBRARY) + $(RM) $(SKETCH_OUTPUTS) + $(RM) -r .depend Test* + +check: all $(SKETCH_OUTPUTS) + @for sketch in $(SKETCH_OUTPUTS); do \ + echo Running $$sketch; \ + $$sketch | grep -i fail; \ + done; exit 0 + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + +%.sketch: %.ino $(LIBRARY) + mkdir -p `dirname $@` + $(CXX) -x c++ $(CXXFLAGS) \ + -include $(TOPDIR)/host/emulation/Arduino.h \ + -include $(TOPDIR)/host/emulation/Arduino.cpp \ + -o $@ $< -L. -lCrypto + +.depend/%.d: %.cpp + @set -e; rm -f $@; mkdir -p `dirname $@`; \ + $(CXX) -MM $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\(.*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +-include $(DEPS) diff --git a/host/Crypto/RNG_host.cpp b/host/Crypto/RNG_host.cpp new file mode 100644 index 00000000..5f123903 --- /dev/null +++ b/host/Crypto/RNG_host.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "RNG.h" +#include "Crypto.h" +#include "ChaCha.h" +#include +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#endif + +// Host emulation for the RNG class, using the native random number generator. + +#define RNG_ROUNDS 20 +#define RNG_REKEY_BLOCKS 16 +#define RNG_MORE_ENTROPY 16384 + +static const char tagRNG[16] = { + 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', + '2', '-', 'b', 'y', 't', 'e', ' ', 'k' +}; + +RNGClass::RNGClass() + : timer(0) +{ + memcpy(block, tagRNG, sizeof(tagRNG)); + memset(block + 4, 0, 48); +} + +RNGClass::~RNGClass() +{ + clean(block); + clean(stream); +} + +void RNGClass::begin(const char *tag, int eepromAddress) +{ +} + +void RNGClass::addNoiseSource(NoiseSource &source) +{ +} + +void RNGClass::setAutoSaveTime(uint16_t minutes) +{ +} + +// Get more entropy from the underlying operating system. +static void getMoreEntropy(uint8_t *data, size_t len) +{ +#if defined(__linux__) + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + perror("/dev/urandom"); + exit(1); + } + int ret = read(fd, data, len); + if (ret != (int)len) { + if (ret < 0) + perror("/dev/urandom"); + close(fd); + exit(1); + } + close(fd); +#else + #warning "TODO: No random entropy on this system!" + memset(data, 0xAA, len); +#endif +} + +void RNGClass::rand(uint8_t *data, size_t len) +{ + // Generate the random data. + uint8_t count = 0; + while (len > 0) { + // Get more entropy from the operating system if necessary. + if (!timer) { + getMoreEntropy((uint8_t *)(block + 4), 48); + rekey(); + timer = RNG_MORE_ENTROPY; + } + + // Force a rekey if we have generated too many blocks in this request. + if (count >= RNG_REKEY_BLOCKS) { + rekey(); + count = 1; + } else { + ++count; + } + + // Increment the low counter word and generate a new keystream block. + ++(block[12]); + ChaCha::hashCore(stream, block, RNG_ROUNDS); + + // Copy the data to the return buffer. + size_t size = (len < 64) ? len : 64; + memcpy(data, stream, size); + data += size; + len -= size; + + // Keep track of the number of bytes we have generated so that + // we can fetch more entropy from the operating system if necessary. + if (timer >= size) + timer -= size; + else + timer = 0; + } + + // Force a rekey after every request. + rekey(); +} + +bool RNGClass::available(size_t len) const +{ + return true; +} + +void RNGClass::stir(const uint8_t *data, size_t len, unsigned int credit) +{ +} + +void RNGClass::save() +{ +} + +void RNGClass::loop() +{ +} + +void RNGClass::destroy() +{ +} + +void RNGClass::rekey() +{ + ++(block[12]); + ChaCha::hashCore(stream, block, RNG_ROUNDS); + memcpy(block + 4, stream, 48); +} + +RNGClass RNG; diff --git a/host/README b/host/README new file mode 100644 index 00000000..c69b017f --- /dev/null +++ b/host/README @@ -0,0 +1,4 @@ + +This directory contains Makefiles and other logic to build some of the +Arduino libraries and programs on a Linux host system. This is intended +to help with testing. It is not a complete Arduino emulation. diff --git a/host/emulation/Arduino.cpp b/host/emulation/Arduino.cpp new file mode 100644 index 00000000..68187f0d --- /dev/null +++ b/host/emulation/Arduino.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +void setup(); +void loop(); + +SerialClass Serial; + +void SerialClass::begin(int baud) +{ +} + +void SerialClass::print(const char *str) +{ + printf("%s", str); +} + +void SerialClass::print(uint8_t value) +{ + printf("%d", value); +} + +void SerialClass::print(uint8_t value, int base) +{ + if (base == HEX) + printf("%x", value); + else + printf("%d", value); +} + +void SerialClass::print(long value) +{ + printf("%ld", value); +} + +void SerialClass::print(long value, int base) +{ + if (base == HEX) + printf("%lx", value); + else + printf("%ld", value); +} + +void SerialClass::print(unsigned long value) +{ + printf("%lu", value); +} + +void SerialClass::print(unsigned long value, int base) +{ + if (base == HEX) + printf("%lx", value); + else + printf("%lu", value); +} + +void SerialClass::print(double value) +{ + printf("%f", value); +} + +void SerialClass::print(char ch) +{ + putc(ch, stdout); +} + +void SerialClass::println(const char *str) +{ + printf("%s\n", str); +} + +void SerialClass::println(uint8_t value) +{ + printf("%d\n", value); +} + +void SerialClass::println(uint8_t value, int base) +{ + if (base == HEX) + printf("%x\n", value); + else + printf("%d\n", value); +} + +void SerialClass::println(long value) +{ + printf("%ld\n", value); +} + +void SerialClass::println(long value, int base) +{ + if (base == HEX) + printf("%lx\n", value); + else + printf("%ld\n", value); +} + +void SerialClass::println(unsigned long value) +{ + printf("%lu\n", value); +} + +void SerialClass::println(unsigned long value, int base) +{ + if (base == HEX) + printf("%lx\n", value); + else + printf("%lu\n", value); +} + +void SerialClass::println(double value) +{ + printf("%f\n", value); +} + +void SerialClass::println(char ch) +{ + putc(ch, stdout); + putc('\n', stdout); +} + +void SerialClass::println() +{ + printf("\n"); +} + +void SerialClass::flush() +{ + fflush(stdout); +} + +unsigned long micros() +{ + struct timespec tv; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tv); + return tv.tv_sec * 1000000UL + tv.tv_nsec / 1000UL; +} + +unsigned long millis() +{ + struct timespec tv; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tv); + return tv.tv_sec * 1000UL + tv.tv_nsec / 1000000UL; +} + +int main(int argc, char *argv[]) +{ + // At the moment, just run the setup() function. + setup(); + return 0; +} diff --git a/host/emulation/Arduino.h b/host/emulation/Arduino.h new file mode 100644 index 00000000..1881c5a6 --- /dev/null +++ b/host/emulation/Arduino.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef ARDUINO_H +#define ARDUINO_H + +#include +#include + +typedef uint8_t byte; + +#define DEC 0 +#define HEX 1 + +class SerialClass +{ +public: + void begin(int baud); + + void print(const char *str); + void print(uint8_t value); + void print(uint8_t value, int base); + void print(long value); + void print(long value, int base); + void print(unsigned long value); + void print(unsigned long value, int base); + void print(double value); + void print(char ch); + + void println(const char *str); + void println(uint8_t value); + void println(uint8_t value, int base); + void println(long value); + void println(long value, int base); + void println(unsigned long value); + void println(unsigned long value, int base); + void println(double value); + void println(char ch); + void println(); + + void flush(); +}; + +extern SerialClass Serial; + +unsigned long micros(); +unsigned long millis(); + +#endif diff --git a/host/emulation/avr/pgmspace.h b/host/emulation/avr/pgmspace.h new file mode 100644 index 00000000..fe1db9d2 --- /dev/null +++ b/host/emulation/avr/pgmspace.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef EMUL_AVR_PGMSPACE_H +#define EMUL_AVR_PGMSPACE_H + +#include +#include +#include + +#define PROGMEM + +#define pgm_read_byte(x) (*(x)) +#define pgm_read_word(x) (*(x)) +#define pgm_read_dword(x) (*(x)) +#define pgm_read_qword(x) (*(x)) + +#define memcpy_P(d,s,l) memcpy((d), (s), (l)) + +#endif diff --git a/libraries/Crypto/examples/TestBigNumberUtil/TestBigNumberUtil.ino b/libraries/Crypto/examples/TestBigNumberUtil/TestBigNumberUtil.ino index 4bef55d8..bdc4ae98 100644 --- a/libraries/Crypto/examples/TestBigNumberUtil/TestBigNumberUtil.ino +++ b/libraries/Crypto/examples/TestBigNumberUtil/TestBigNumberUtil.ino @@ -57,7 +57,7 @@ void bytesFromString(uint8_t *x, size_t xsize, const char *str) { uint8_t ch; size_t posn; - memset(x, 0, sizeof(limb_t) * xsize); + memset(x, 0, xsize); while ((ch = pgm_read_byte((uint8_t *)str)) != '\0') { if (ch >= '0' && ch <= '9') { // Quick and simple method to multiply by 10 and add the new digit. diff --git a/libraries/Crypto/examples/TestSHA3_256/TestSHA3_256.ino b/libraries/Crypto/examples/TestSHA3_256/TestSHA3_256.ino index 51864638..14159d74 100644 --- a/libraries/Crypto/examples/TestSHA3_256/TestSHA3_256.ino +++ b/libraries/Crypto/examples/TestSHA3_256/TestSHA3_256.ino @@ -147,8 +147,6 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) void testHash(Hash *hash, const struct TestHashVector *test) { bool ok; - const char *str; - uint8_t ch; Serial.print(test->name); Serial.print(" ... "); @@ -239,8 +237,8 @@ void testHMAC(Hash *hash, size_t keyLen) // Construct the expected result with a simple HMAC implementation. memset(buffer, (uint8_t)keyLen, keyLen); hashKey(hash, buffer, keyLen, 0x36); - memset(buffer, 0xBA, sizeof(buffer)); - hash->update(buffer, sizeof(buffer)); + memset(buffer, 0xBA, sizeof(testVectorSHA3_256_5)); + hash->update(buffer, sizeof(testVectorSHA3_256_5)); hash->finalize(result, HASH_SIZE); memset(buffer, (uint8_t)keyLen, keyLen); hashKey(hash, buffer, keyLen, 0x5C); @@ -249,8 +247,8 @@ void testHMAC(Hash *hash, size_t keyLen) // Now use the library to compute the HMAC. hash->resetHMAC(buffer, keyLen); - memset(buffer, 0xBA, sizeof(buffer)); - hash->update(buffer, sizeof(buffer)); + memset(buffer, 0xBA, sizeof(testVectorSHA3_256_5)); + hash->update(buffer, sizeof(testVectorSHA3_256_5)); memset(buffer, (uint8_t)keyLen, keyLen); hash->finalizeHMAC(buffer, keyLen, buffer, HASH_SIZE); diff --git a/libraries/Crypto/examples/TestSHA3_512/TestSHA3_512.ino b/libraries/Crypto/examples/TestSHA3_512/TestSHA3_512.ino index 474e0c36..85dddf6d 100644 --- a/libraries/Crypto/examples/TestSHA3_512/TestSHA3_512.ino +++ b/libraries/Crypto/examples/TestSHA3_512/TestSHA3_512.ino @@ -153,8 +153,6 @@ bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc) void testHash(Hash *hash, const struct TestHashVector *test) { bool ok; - const char *str; - uint8_t ch; Serial.print(test->name); Serial.print(" ... "); diff --git a/libraries/Crypto/examples/TestSHAKE128/TestSHAKE128.ino b/libraries/Crypto/examples/TestSHAKE128/TestSHAKE128.ino index 5d1acc1c..806f0616 100644 --- a/libraries/Crypto/examples/TestSHAKE128/TestSHAKE128.ino +++ b/libraries/Crypto/examples/TestSHAKE128/TestSHAKE128.ino @@ -243,8 +243,6 @@ bool testSHAKE_N(SHAKE *shake, const struct TestHashVectorSHAKE *test, size_t in void testSHAKE(SHAKE *shake, const struct TestHashVectorSHAKE *test) { bool ok; - const char *str; - uint8_t ch; size_t dataLen; memcpy_P(&dataLen, &(test->dataLen), sizeof(size_t)); diff --git a/libraries/Crypto/examples/TestSHAKE256/TestSHAKE256.ino b/libraries/Crypto/examples/TestSHAKE256/TestSHAKE256.ino index 074bd48c..dede3e62 100644 --- a/libraries/Crypto/examples/TestSHAKE256/TestSHAKE256.ino +++ b/libraries/Crypto/examples/TestSHAKE256/TestSHAKE256.ino @@ -239,8 +239,6 @@ bool testSHAKE_N(SHAKE *shake, const struct TestHashVectorSHAKE *test, size_t in void testSHAKE(SHAKE *shake, const struct TestHashVectorSHAKE *test) { bool ok; - const char *str; - uint8_t ch; size_t dataLen; memcpy_P(&dataLen, &(test->dataLen), sizeof(size_t)); diff --git a/libraries/Crypto/examples/TestXTS/TestXTS.ino b/libraries/Crypto/examples/TestXTS/TestXTS.ino index 7fd64e69..cad61064 100644 --- a/libraries/Crypto/examples/TestXTS/TestXTS.ino +++ b/libraries/Crypto/examples/TestXTS/TestXTS.ino @@ -31,6 +31,7 @@ This example runs tests on the XTS implementation to verify correct behaviour. #include #include #include +#include #define MAX_SECTOR_SIZE 64 diff --git a/libraries/Crypto/utility/EndianUtil.h b/libraries/Crypto/utility/EndianUtil.h index 29c2c150..b4e31aa7 100644 --- a/libraries/Crypto/utility/EndianUtil.h +++ b/libraries/Crypto/utility/EndianUtil.h @@ -25,6 +25,8 @@ #include +#if !defined(HOST_BUILD) + // CPU is assumed to be little endian. Edit this file if you // need to port this library to a big endian CPU. @@ -63,4 +65,13 @@ })) #define be64toh(x) (htobe64((x))) +#else // HOST_BUILD + +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define CRYPTO_LITTLE_ENDIAN 1 +#endif + +#endif // HOST_BUILD + #endif