projectuser
2019-07-08 827102212c4403e5c454b77bc44b40310f23fa34
类库新建
103个文件已添加
1个文件已修改
27987 ■■■■■ 已修改文件
README.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/ESP8266/ESP8266.ino 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/w5500/w5500.ino 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
library.properties 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/aliIotLink.cpp 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/aliIotLink.h 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AES.h 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AES128.cpp 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AES192.cpp 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AES256.cpp 401 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AESCommon.cpp 363 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AESEsp32.cpp 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AuthenticatedCipher.cpp 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/AuthenticatedCipher.h 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BLAKE2b.cpp 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BLAKE2b.h 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BLAKE2s.cpp 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BLAKE2s.h 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BigNumberUtil.cpp 769 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BigNumberUtil.h 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BlockCipher.cpp 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/BlockCipher.h 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/CTR.cpp 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/CTR.h 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/ChaCha.cpp 281 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/ChaCha.h 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/ChaChaPoly.cpp 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/ChaChaPoly.h 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Cipher.cpp 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Cipher.h 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Crypto.cpp 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Crypto.h 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Curve25519.cpp 1610 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Curve25519.h 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/EAX.cpp 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/EAX.h 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Ed25519.cpp 642 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Ed25519.h 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/GCM.cpp 335 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/GCM.h 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/GF128.cpp 571 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/GF128.h 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/GHASH.cpp 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/GHASH.h 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Hash.cpp 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Hash.h 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/KeccakCore.cpp 2013 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/KeccakCore.h 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/NoiseSource.cpp 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/NoiseSource.h 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/OMAC.cpp 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/OMAC.h 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/P521.cpp 1642 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/P521.h 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Poly1305.cpp 345 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/Poly1305.h 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/RNG.cpp 1004 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/RNG.h 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHA256.cpp 258 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHA256.h 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHA3.cpp 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHA3.h 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHA512.cpp 274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHA512.h 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHAKE.cpp 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/SHAKE.h 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/XOF.cpp 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/XOF.h 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/XTS.cpp 437 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/XTS.h 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestAES/TestAES.ino 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestAESSmall/TestAESSmall.ino 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestAESTiny/TestAESTiny.ino 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestBLAKE2b/TestBLAKE2b.ino 410 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino 429 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestBigNumberUtil/TestBigNumberUtil.ino 378 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestCTR/TestCTR.ino 231 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestChaCha/TestChaCha.ino 422 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestChaChaPoly/TestChaChaPoly.ino 452 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestCurve25519/TestCurve25519.ino 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestCurve25519Math/TestCurve25519Math.ino 683 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestEAX/TestEAX.ino 558 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestEd25519/TestEd25519.ino 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestGCM/TestGCM.ino 584 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestGHASH/TestGHASH.ino 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestP521/TestP521.ino 523 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestP521Math/TestP521Math.ino 612 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestPoly1305/TestPoly1305.ino 238 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestRNG/TestRNG.ino 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestSHA256/TestSHA256.ino 323 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestSHA3_256/TestSHA3_256.ino 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestSHA3_512/TestSHA3_512.ino 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestSHA512/TestSHA512.ino 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestSHAKE128/TestSHAKE128.ino 369 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestSHAKE256/TestSHAKE256.ino 365 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/examples/TestXTS/TestXTS.ino 480 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/keywords.txt 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/library.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/utility/EndianUtil.h 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/utility/LimbUtil.h 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/utility/ProgMemUtil.h 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/Crypto/utility/RotateUtil.h 696 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/mqtt/PubSubClient.cpp 607 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/mqtt/PubSubClient.h 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -1,4 +1,5 @@
## aliIotLink
连接阿里MQTT服务的通用类库
## 阿里云物联网平台的 arduino连接工具包
* 目前实现了订阅消息与平台推送消息的回调
* 只能发布QoS 0消息,可以订阅QoS 0或QoS 1
* 目前已支持 arduino UNO  ,MEGA2560 (基于W5100,W5500),esp8266,esp8285,esp32 (wifi)
examples/ESP8266/ESP8266.ino
New file
@@ -0,0 +1,56 @@
#include <aliIotLink.h>
#include <ESP8266WiFi.h>
const char* ssid = "WIFI-SSID";
const char* password = "12345678";
static const char ProductKey[] PROGMEM = "a1BllGqYfBO";
static const char DeviceName[] PROGMEM = "QNfNlOW1l9uTY2V0Dw2E";
static const char DeviceSecret[] PROGMEM = "jIM4j0tphyiXhx4yVzuv2BcF1bz916Oo";
static const char postTopic[]  PROGMEM = "";   //上报消息topic
static const char setTopic[]  PROGMEM = "";    //服务器消息topic
WiFiClient espClient;   //实例化 wifi网络
PubSubClient client(espClient); //将网络传入MQTT
AliIotLink aliLink(client);  //将mqtt传入服务
//回调函数
void Callbacks(char* topic, byte* payload, unsigned int length)
{
    //回调功能演示,将监听到的消息直接打印到串口
  Serial.print(topic);
  Serial.print(":");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}
void setup()
{
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);   //配置为客户端模式
  WiFi.begin(ssid, password);  //初始化并且链接wifi
  while (WiFi.status() != WL_CONNECTED)  //等待wifi连接
  {
    delay(500);
    Serial.print(".");
  }
  aliLink.subTopic(FPSTR(setTopic));   //订阅服务器下行消息
  aliLink.setCallback(Callbacks);   //注册下发消息回调函数
  aliLink.begin(FPSTR(DeviceName),FPSTR(ProductKey),FPSTR(DeviceSecret));  //完成初始化配置 三元素(DeviceName,ProductKey,DeviceSecret)
}
void loop()
{
  if (aliLink.state() != 0) // 显示连接错误码,实际项目不需要
  {
    Serial.println(aliLink.state());
  }
  aliLink.loop();  //循环维持心跳与消息触发,应尽可能多的执行
}
examples/w5500/w5500.ino
New file
@@ -0,0 +1,54 @@
#include <aliIotLink.h>
#include <SPI.h>
#include <Ethernet2.h>
//W5500 链接阿里云
byte mac[] = {0x00, 0xED, 0xBA, 0xFE, 0xFE, 0xED };  //MAC地址
static const char ProductKey[] PROGMEM = "a1BllGqYfBO";
static const char DeviceName[] PROGMEM = "QNfNlOW1l9uTY2V0Dw2E";
static const char DeviceSecret[] PROGMEM = "jIM4j0tphyiXhx4yVzuv2BcF1bz916Oo";
static const char postTopic[]  PROGMEM = "";   //上报消息topic
static const char setTopic[]  PROGMEM = "";    //服务器消息topic
EthernetClient ethClient;  //实例化以太网
PubSubClient client(ethClient); //将网络传入MQTT
AliIotLink aliLink(client);   //将mqtt传入服务
//回调函数
void Callbacks(char* topic, byte* payload, unsigned int length)
{
    //回调功能演示,将监听到的消息直接打印到串口
  Serial.print(topic);
  Serial.print(":");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}
void setup()
{
  Serial.begin(115200);
  Ethernet.begin(mac);  //初始化以太网
  aliLink.subTopic(FPSTR(setTopic));   //订阅服务器下行消息
  aliLink.setCallback(Callbacks);   //注册下发消息回调函数
  aliLink.begin(FPSTR(DeviceName),FPSTR(ProductKey),FPSTR(DeviceSecret));  //完成初始化配置 三元素(DeviceName,ProductKey,DeviceSecret)
}
void loop()
{
  if (aliLink.state() != 0) // 显示连接错误码,实际项目不需要
  {
    Serial.println(aliLink.state());
  }
  aliLink.loop();  //循环维持心跳与消息触发,应尽可能多的执行
}
library.properties
New file
@@ -0,0 +1,9 @@
name=aliIotLink
version=0.0.1
author=MiNiQiang
maintainer=MiNiQiang
sentence=
paragraph=Support Arduino, ESP8266, ESP8285, ESP32.
category=Communication
url=https://github.com/MINI-Qiang/aliIotLink
architectures=*
src/aliIotLink.cpp
New file
@@ -0,0 +1,215 @@
#include "aliIotLink.h"
SHA256 sha256;
AliIotLink::AliIotLink(PubSubClient& client)
{
    _client = &client;
}
void AliIotLink::begin()
{
  //randomSeed(analogRead(A0));   //获取IO随机值【非安全的伪随机】作为种子
  //delayMicroseconds(random(0,10000));   //延迟随机时间
  generateClientId();
  readUrl();
  readUser();
  readPasswd();
  _client->setServer(_URL.c_str(),_port); //写入服务器名称与端口号
}
void AliIotLink::begin(String __DeviceName,String __ProductKey,String __DeviceSecret)
{
    _Id = __DeviceName;
    _DeviceName = __DeviceName;
    _ProductKey = __ProductKey;
    _DeviceSecret = __DeviceSecret;
    //randomSeed(analogRead(A0));
    //delayMicroseconds(random(0,10000));
    generateClientId();
    readUrl();
    readUser();
    readPasswd();
    _client->setServer(_URL.c_str(),_port);  //写入服务器名称与端口号
}
void AliIotLink::writeUrl(String __ServerUrl)    // 设置登录网址
{
    //_ServerUrl = __ServerUrl;
}
//服务器端口设置
void AliIotLink::writePort(uint16_t __port)
{
    _port = __port;
}
//硬件设备名称
void AliIotLink::writeID(String __Id)
{
    _Id = __Id;
}
// 设置设备硬件标签名称【阿里云提供】
void AliIotLink::writeDeviceName(String __DeviceName)
{
    _DeviceName = __DeviceName;
}
//【阿里云提供】
void AliIotLink::writeProductKey(String __ProductKey)
{
    _ProductKey = __ProductKey;
}
//【阿里云提供】
void AliIotLink::writeDeviceSecret(String __DeviceSecret)
{
    _DeviceSecret = __DeviceSecret;
}
void AliIotLink::generateClientId()
{
    //ID+参数+随机数+结尾符号
    randomSeed(micros());
    Times  =random(0, 65535);
    _ClientId = _Id + FPSTR(_ClientIdSuffix) + Times +"|";
}
//获取合成好的登录用的ClientId
String AliIotLink::readClientId()
{
    return _ClientId;
}
//合成访问网址
 String AliIotLink::readUrl()
 {
     _URL = _ProductKey + F(".") + FPSTR(_ServerUrl);
     return _URL;
 }
 //合成访问用户名
 String AliIotLink::readUser()
 {
     _Username = _DeviceName + "&" + _ProductKey ;
     return _Username;
 }
 //合成访问密码
 String AliIotLink::readPasswd()
 {
     String _Passwd =  "clientId" + _Id + "deviceName" + _DeviceName +"productKey"+_ProductKey + "timestamp" + Times;
     _PasswdHash = "";
     byte hashData[64];
     HMAC(_DeviceSecret.c_str(), 32, _Passwd.c_str(), _Passwd.length(), hashData);
     for (int i = 0; i < 32; i++)  //hash 固定长度
     {
        _PasswdHash = _PasswdHash + "0123456789ABCDEF"[hashData[i] >> 4];
         _PasswdHash = _PasswdHash + "0123456789ABCDEF"[hashData[i] & 0xf];
     }
     //
     return _PasswdHash;
     //返回HASH密文
 }
 //===================mqtt部分=====================
 bool AliIotLink::connect()
 {
     return _client->connect(_ClientId.c_str(),_Username.c_str(),_PasswdHash.c_str());   //像服务器传递 ClientId,用户名,密码
 }
 //重连
 void AliIotLink::reconnect()
 {
   while(!_client->connected()) //检查网络网络是否不正常,断开的网络会锁定重试
   {
      if (connect())   //重连并判断是否成功
      {
          //成功
          for(byte a = 0;a<TopicNum;a++)
          {
              subscribe(TopicName[a].c_str());
          }
          //填写上线订阅,应该是个String数组传入循环订阅处理
      }
    else
        {
            //链接失败
           delay(5000);   //暂停5秒钟重试
        }
  }
 }
 //循环检测
 void AliIotLink::loop()
 {
   if (!_client->connected())
   {
    reconnect();
   }
    _client->loop();
}
int AliIotLink::state()    //错误消息返回
{
    return _client->state();
}
//回调函数
void AliIotLink::setCallback(MQTT_CALLBACK_SIGNATURE)
{
    _client->setCallback(callback);
    //SerialUSB.println(callback);
}
//监听Topic
void AliIotLink::subscribe(const char* topic)
{
    _client->subscribe(topic);
}
//推送消息
void AliIotLink::publish(const char* topic, const char* payload)
{
    _client->publish(topic,payload);
}
//登记topic
void AliIotLink::subTopic(String topic)
{
    TopicName[TopicNum] = topic;
    TopicNum++;
    if(TopicNum > MQTT_Topic_Quantity)
    {
        TopicNum = MQTT_Topic_Quantity;
    }
}
void AliIotLink::HMAC( char const *key, byte KeySize,  char const *data, byte dataSize, byte *hashData)
{
  uint8_t result[32];
  sha256.resetHMAC(key, KeySize);  //传入KEY,和key长度
  sha256.update(data, dataSize);// 传输 hash明文
  sha256.finalizeHMAC(key, KeySize, result, sizeof(result)); // 计算
  for (byte a = 0; a < sizeof(result); a++) //传出签名
  {
    *(hashData + a) = result[a];
  }
}
src/aliIotLink.h
New file
@@ -0,0 +1,77 @@
#ifndef aliIotLink_H
#define aliIotLink_H
#include <Arduino.h>
#include "modules/mqtt/PubSubClient.h"
#include "modules/Crypto/SHA256.h"
#include "modules/Crypto/Crypto.h"
#define MQTT_Topic_Quantity  2
static const char _ServerUrl[] PROGMEM = "iot-as-mqtt.cn-shanghai.aliyuncs.com";
static const char _ClientIdSuffix[] PROGMEM = "|securemode=3,signmethod=hmacsha256,timestamp=";
class AliIotLink
{
    public:
        AliIotLink(PubSubClient& client);
        void begin();
        void begin(String __DeviceName,String __ProductKey,String __DeviceSecret);
        void writeUrl(String __ServerUrl);    // 设置登录网址
        void writePort(uint16_t __port);   //服务器端口
        void writeID(String __Id);    //设备ID
        void writeDeviceName(String __DeviceName);  // 设置设备名称
        void writeProductKey(String __ProductKey);
        void writeDeviceSecret(String __DeviceSecret);
        void  generateClientId();  //获取登录的设备ID
        bool connect();   //链接服务器
        void subTopic(String topic);    //配置订阅topic
        void publish(const char* topic, const char * payload);  //推送消息
        void setCallback(MQTT_CALLBACK_SIGNATURE);//注册回调函数
        void reconnect();
        void loop();  //心跳维持与重连
        int state();   //错误消息返回
    private:
        //私有函数
        void HMAC(char const *key, byte KeySize, char const *data, byte dataSize, byte *hashData);
        void subscribe(const char* topic);  //监听Topic
        String readClientId();  //获取登录的设备ID
        String readUrl();
        String readUser();
        String readPasswd();
        //登录用四元素
        //私有对象
        PubSubClient* _client;    //mqtt接口
        //私有变量
        String TopicName[MQTT_Topic_Quantity];
        //String _ServerUrl = "iot-as-mqtt.cn-shanghai.aliyuncs.com";
        String _Id;
        //String _ClientIdSuffix = "|securemode=3,signmethod=hmacsha256,timestamp=";
        uint16_t _port = 1883;
        uint16_t Times;
        uint8_t TopicNum =0;   //topic计数器
        //
        String _URL;
        String _ClientId;
        String _Username;
        String _PasswdHash;
        //三元素
        String _DeviceName;
        String _ProductKey;
        String _DeviceSecret;
};
#endif
src/modules/Crypto/AES.h
New file
@@ -0,0 +1,256 @@
/*
 * Copyright (C) 2015,2018 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 CRYPTO_AES_h
#define CRYPTO_AES_h
#include "BlockCipher.h"
// Determine which AES implementation to export to applications.
#if defined(ESP32)
#define CRYPTO_AES_ESP32 1
#else
#define CRYPTO_AES_DEFAULT 1
#endif
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
class AESTiny128;
class AESTiny256;
class AESSmall128;
class AESSmall256;
class AESCommon : public BlockCipher
{
public:
    virtual ~AESCommon();
    size_t blockSize() const;
    void encryptBlock(uint8_t *output, const uint8_t *input);
    void decryptBlock(uint8_t *output, const uint8_t *input);
    void clear();
protected:
    AESCommon();
    /** @cond aes_internal */
    uint8_t rounds;
    uint8_t *schedule;
    static void subBytesAndShiftRows(uint8_t *output, const uint8_t *input);
    static void inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input);
    static void mixColumn(uint8_t *output, uint8_t *input);
    static void inverseMixColumn(uint8_t *output, const uint8_t *input);
    static void keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration);
    static void applySbox(uint8_t *output, const uint8_t *input);
    /** @endcond */
    friend class AESTiny128;
    friend class AESTiny256;
    friend class AESSmall128;
    friend class AESSmall256;
};
class AES128 : public AESCommon
{
public:
    AES128();
    virtual ~AES128();
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
private:
    uint8_t sched[176];
};
class AES192 : public AESCommon
{
public:
    AES192();
    virtual ~AES192();
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
private:
    uint8_t sched[208];
};
class AES256 : public AESCommon
{
public:
    AES256();
    virtual ~AES256();
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
private:
    uint8_t sched[240];
};
class AESTiny256 : public BlockCipher
{
public:
    AESTiny256();
    virtual ~AESTiny256();
    size_t blockSize() const;
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
    void encryptBlock(uint8_t *output, const uint8_t *input);
    void decryptBlock(uint8_t *output, const uint8_t *input);
    void clear();
private:
    uint8_t schedule[32];
};
class AESSmall256 : public AESTiny256
{
public:
    AESSmall256();
    virtual ~AESSmall256();
    bool setKey(const uint8_t *key, size_t len);
    void decryptBlock(uint8_t *output, const uint8_t *input);
    void clear();
private:
    uint8_t reverse[32];
};
class AESTiny128 : public BlockCipher
{
public:
    AESTiny128();
    virtual ~AESTiny128();
    size_t blockSize() const;
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
    void encryptBlock(uint8_t *output, const uint8_t *input);
    void decryptBlock(uint8_t *output, const uint8_t *input);
    void clear();
private:
    uint8_t schedule[16];
};
class AESSmall128 : public AESTiny128
{
public:
    AESSmall128();
    virtual ~AESSmall128();
    bool setKey(const uint8_t *key, size_t len);
    void decryptBlock(uint8_t *output, const uint8_t *input);
    void clear();
private:
    uint8_t reverse[16];
};
#endif // CRYPTO_AES_DEFAULT
#if defined(CRYPTO_AES_ESP32)
// "hwcrypto/aes.h" includes "rom/aes.h" which defines global enums for
// AES128, AES192, and AES256.  The enum definitions interfere with the
// definition of the same-named classes below.  The #define's and #undef's
// here work around the problem by defining the enums to different names.
#define AES128 AES128_enum
#define AES192 AES192_enum
#define AES256 AES256_enum
#include "hwcrypto/aes.h"
#undef AES128
#undef AES192
#undef AES256
class AESCommon : public BlockCipher
{
public:
    virtual ~AESCommon();
    size_t blockSize() const;
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
    void encryptBlock(uint8_t *output, const uint8_t *input);
    void decryptBlock(uint8_t *output, const uint8_t *input);
    void clear();
protected:
    AESCommon(uint8_t keySize);
private:
    esp_aes_context ctx;
};
class AES128 : public AESCommon
{
public:
    AES128() : AESCommon(16) {}
    virtual ~AES128();
};
class AES192 : public AESCommon
{
public:
    AES192() : AESCommon(24) {}
    virtual ~AES192();
};
class AES256 : public AESCommon
{
public:
    AES256() : AESCommon(32) {}
    virtual ~AES256();
};
// The ESP32 AES context is so small that it already qualifies as "tiny".
typedef AES128 AESTiny128;
typedef AES256 AESTiny256;
typedef AES128 AESSmall128;
typedef AES256 AESSmall256;
#endif // CRYPTO_AES_ESP32
#endif
src/modules/Crypto/AES128.cpp
New file
@@ -0,0 +1,356 @@
/*
 * Copyright (C) 2015,2018 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 "AES.h"
#include "Crypto.h"
#include <string.h>
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
/**
 * \class AES128 AES.h <AES.h>
 * \brief AES block cipher with 128-bit keys.
 *
 * \sa AES192, AES256, AESTiny128, AESSmall128
 */
/**
 * \brief Constructs an AES 128-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AES128::AES128()
{
    rounds = 10;
    schedule = sched;
}
AES128::~AES128()
{
    clean(sched);
}
/**
 * \brief Size of a 128-bit AES key in bytes.
 * \return Always returns 16.
 */
size_t AES128::keySize() const
{
    return 16;
}
bool AES128::setKey(const uint8_t *key, size_t len)
{
    if (len != 16)
        return false;
    // Copy the key itself into the first 16 bytes of the schedule.
    uint8_t *schedule = sched;
    memcpy(schedule, key, 16);
    // Expand the key schedule until we have 176 bytes of expanded key.
    uint8_t iteration = 1;
    uint8_t n = 16;
    uint8_t w = 4;
    while (n < 176) {
        if (w == 4) {
            // Every 16 bytes (4 words) we need to apply the key schedule core.
            keyScheduleCore(schedule + 16, schedule + 12, iteration);
            schedule[16] ^= schedule[0];
            schedule[17] ^= schedule[1];
            schedule[18] ^= schedule[2];
            schedule[19] ^= schedule[3];
            ++iteration;
            w = 0;
        } else {
            // Otherwise just XOR the word with the one 16 bytes previous.
            schedule[16] = schedule[12] ^ schedule[0];
            schedule[17] = schedule[13] ^ schedule[1];
            schedule[18] = schedule[14] ^ schedule[2];
            schedule[19] = schedule[15] ^ schedule[3];
        }
        // Advance to the next word in the schedule.
        schedule += 4;
        n += 4;
        ++w;
    }
    return true;
}
/**
 * \class AESTiny128 AES.h <AES.h>
 * \brief AES block cipher with 128-bit keys and tiny memory usage.
 *
 * This class differs from the AES128 class in the following ways:
 *
 * \li RAM requirements are vastly reduced.  The key is stored directly
 * and then expanded to the full key schedule round by round.  The setKey()
 * method is very fast because of this.
 * \li Performance of encryptBlock() is slower than for AES128 due to
 * expanding the key on the fly rather than ahead of time.
 * \li The decryptBlock() function is not supported, which means that CBC
 * mode cannot be used but the CTR, CFB, OFB, EAX, and GCM modes can be used.
 *
 * This class is useful when RAM is at a premium, CBC mode is not required,
 * and reduced encryption performance is not a hindrance to the application.
 *
 * The companion AESSmall128 class supports decryptBlock() at the cost of
 * some additional memory and slower setKey() times.
 *
 * \sa AESSmall128, AES128
 */
/** @cond */
// Helper macros.
#define KCORE(n) \
    do { \
        AESCommon::keyScheduleCore(temp, schedule + 12, (n)); \
        schedule[0] ^= temp[0]; \
        schedule[1] ^= temp[1]; \
        schedule[2] ^= temp[2]; \
        schedule[3] ^= temp[3]; \
    } while (0)
#define KXOR(a, b) \
    do { \
        schedule[(a) * 4] ^= schedule[(b) * 4]; \
        schedule[(a) * 4 + 1] ^= schedule[(b) * 4 + 1]; \
        schedule[(a) * 4 + 2] ^= schedule[(b) * 4 + 2]; \
        schedule[(a) * 4 + 3] ^= schedule[(b) * 4 + 3]; \
    } while (0)
/** @endcond */
/**
 * \brief Constructs an AES 128-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AESTiny128::AESTiny128()
{
}
AESTiny128::~AESTiny128()
{
    clean(schedule);
}
/**
 * \brief Size of an AES block in bytes.
 * \return Always returns 16.
 */
size_t AESTiny128::blockSize() const
{
    return 16;
}
/**
 * \brief Size of a 128-bit AES key in bytes.
 * \return Always returns 16.
 */
size_t AESTiny128::keySize() const
{
    return 16;
}
bool AESTiny128::setKey(const uint8_t *key, size_t len)
{
    if (len == 16) {
        // Make a copy of the key - it will be expanded in encryptBlock().
        memcpy(schedule, key, 16);
        return true;
    }
    return false;
}
void AESTiny128::encryptBlock(uint8_t *output, const uint8_t *input)
{
    uint8_t schedule[16];
    uint8_t posn;
    uint8_t round;
    uint8_t state1[16];
    uint8_t state2[16];
    uint8_t temp[4];
    // Start with the key in the schedule buffer.
    memcpy(schedule, this->schedule, 16);
    // Copy the input into the state and XOR with the key schedule.
    for (posn = 0; posn < 16; ++posn)
        state1[posn] = input[posn] ^ schedule[posn];
    // Perform the first 9 rounds of the cipher.
    for (round = 1; round <= 9; ++round) {
        // Expand the next 16 bytes of the key schedule.
        KCORE(round);
        KXOR(1, 0);
        KXOR(2, 1);
        KXOR(3, 2);
        // Encrypt using the key schedule.
        AESCommon::subBytesAndShiftRows(state2, state1);
        AESCommon::mixColumn(state1,      state2);
        AESCommon::mixColumn(state1 + 4,  state2 + 4);
        AESCommon::mixColumn(state1 + 8,  state2 + 8);
        AESCommon::mixColumn(state1 + 12, state2 + 12);
        for (posn = 0; posn < 16; ++posn)
            state1[posn] ^= schedule[posn];
    }
    // Expand the final 16 bytes of the key schedule.
    KCORE(10);
    KXOR(1, 0);
    KXOR(2, 1);
    KXOR(3, 2);
    // Perform the final round.
    AESCommon::subBytesAndShiftRows(state2, state1);
    for (posn = 0; posn < 16; ++posn)
        output[posn] = state2[posn] ^ schedule[posn];
}
void AESTiny128::decryptBlock(uint8_t *output, const uint8_t *input)
{
    // Decryption is not supported by AESTiny128.
}
void AESTiny128::clear()
{
    clean(schedule);
}
/**
 * \class AESSmall128 AES.h <AES.h>
 * \brief AES block cipher with 128-bit keys and reduced memory usage.
 *
 * This class differs from the AES128 class in that the RAM requirements are
 * vastly reduced.  The key schedule is expanded round by round instead of
 * being generated and stored by setKey().  The performance of encryption
 * and decryption is slightly less because of this.
 *
 * This class is useful when RAM is at a premium and reduced encryption
 * performance is not a hindrance to the application.
 *
 * The companion AESTiny128 class uses even less RAM but only supports the
 * encryptBlock() operation.  Block cipher modes like CTR, EAX, and GCM
 * do not need the decryptBlock() operation, so AESTiny128 may be a better
 * option than AESSmall128 for many applications.
 *
 * \sa AESTiny128, AES128
 */
/**
 * \brief Constructs an AES 128-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AESSmall128::AESSmall128()
{
}
AESSmall128::~AESSmall128()
{
    clean(reverse);
}
bool AESSmall128::setKey(const uint8_t *key, size_t len)
{
    uint8_t *schedule;
    uint8_t round;
    uint8_t temp[4];
    // Set the encryption key first.
    if (!AESTiny128::setKey(key, len))
        return false;
    // Expand the key schedule up to the last round which gives
    // us the round keys to use for the final two rounds.  We can
    // then work backwards from there in decryptBlock().
    schedule = reverse;
    memcpy(schedule, key, 16);
    for (round = 1; round <= 10; ++round) {
        KCORE(round);
        KXOR(1, 0);
        KXOR(2, 1);
        KXOR(3, 2);
    }
    // Key is ready to go.
    return true;
}
void AESSmall128::decryptBlock(uint8_t *output, const uint8_t *input)
{
    uint8_t schedule[16];
    uint8_t round;
    uint8_t posn;
    uint8_t state1[16];
    uint8_t state2[16];
    uint8_t temp[4];
    // Start with the end of the decryption schedule.
    memcpy(schedule, reverse, 16);
    // Copy the input into the state and reverse the final round.
    for (posn = 0; posn < 16; ++posn)
        state1[posn] = input[posn] ^ schedule[posn];
    AESCommon::inverseShiftRowsAndSubBytes(state2, state1);
    KXOR(3, 2);
    KXOR(2, 1);
    KXOR(1, 0);
    KCORE(10);
    // Perform the next 9 rounds of the decryption process.
    for (round = 9; round >= 1; --round) {
        // Decrypt using the key schedule.
        for (posn = 0; posn < 16; ++posn)
            state2[posn] ^= schedule[posn];
        AESCommon::inverseMixColumn(state1,      state2);
        AESCommon::inverseMixColumn(state1 + 4,  state2 + 4);
        AESCommon::inverseMixColumn(state1 + 8,  state2 + 8);
        AESCommon::inverseMixColumn(state1 + 12, state2 + 12);
        AESCommon::inverseShiftRowsAndSubBytes(state2, state1);
        // Expand the next 16 bytes of the key schedule in reverse.
        KXOR(3, 2);
        KXOR(2, 1);
        KXOR(1, 0);
        KCORE(round);
    }
    // Reverse the initial round and create the output words.
    for (posn = 0; posn < 16; ++posn)
        output[posn] = state2[posn] ^ schedule[posn];
}
void AESSmall128::clear()
{
    clean(reverse);
    AESTiny128::clear();
}
#endif // CRYPTO_AES_DEFAULT
src/modules/Crypto/AES192.cpp
New file
@@ -0,0 +1,102 @@
/*
 * 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 "AES.h"
#include "Crypto.h"
#include <string.h>
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
/**
 * \class AES192 AES.h <AES.h>
 * \brief AES block cipher with 192-bit keys.
 *
 * \sa AES128, AES256
 */
/**
 * \brief Constructs an AES 192-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AES192::AES192()
{
    rounds = 12;
    schedule = sched;
}
AES192::~AES192()
{
    clean(sched);
}
/**
 * \brief Size of a 192-bit AES key in bytes.
 * \return Always returns 24.
 */
size_t AES192::keySize() const
{
    return 24;
}
bool AES192::setKey(const uint8_t *key, size_t len)
{
    if (len != 24)
        return false;
    // Copy the key itself into the first 24 bytes of the schedule.
    uint8_t *schedule = sched;
    memcpy(schedule, key, 24);
    // Expand the key schedule until we have 208 bytes of expanded key.
    uint8_t iteration = 1;
    uint8_t n = 24;
    uint8_t w = 6;
    while (n < 208) {
        if (w == 6) {
            // Every 24 bytes (6 words) we need to apply the key schedule core.
            keyScheduleCore(schedule + 24, schedule + 20, iteration);
            schedule[24] ^= schedule[0];
            schedule[25] ^= schedule[1];
            schedule[26] ^= schedule[2];
            schedule[27] ^= schedule[3];
            ++iteration;
            w = 0;
        } else {
            // Otherwise just XOR the word with the one 24 bytes previous.
            schedule[24] = schedule[20] ^ schedule[0];
            schedule[25] = schedule[21] ^ schedule[1];
            schedule[26] = schedule[22] ^ schedule[2];
            schedule[27] = schedule[23] ^ schedule[3];
        }
        // Advance to the next word in the schedule.
        schedule += 4;
        n += 4;
        ++w;
    }
    return true;
}
#endif // CRYPTO_AES_DEFAULT
src/modules/Crypto/AES256.cpp
New file
@@ -0,0 +1,401 @@
/*
 * Copyright (C) 2015,2018 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 "AES.h"
#include "Crypto.h"
#include <string.h>
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
/**
 * \class AES256 AES.h <AES.h>
 * \brief AES block cipher with 256-bit keys.
 *
 * \sa AES128, AES192, AESTiny256, AESSmall256
 */
/**
 * \brief Constructs an AES 256-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AES256::AES256()
{
    rounds = 14;
    schedule = sched;
}
AES256::~AES256()
{
    clean(sched);
}
/**
 * \brief Size of a 256-bit AES key in bytes.
 * \return Always returns 32.
 */
size_t AES256::keySize() const
{
    return 32;
}
bool AES256::setKey(const uint8_t *key, size_t len)
{
    if (len != 32)
        return false;
    // Copy the key itself into the first 32 bytes of the schedule.
    uint8_t *schedule = sched;
    memcpy(schedule, key, 32);
    // Expand the key schedule until we have 240 bytes of expanded key.
    uint8_t iteration = 1;
    uint8_t n = 32;
    uint8_t w = 8;
    while (n < 240) {
        if (w == 8) {
            // Every 32 bytes (8 words) we need to apply the key schedule core.
            keyScheduleCore(schedule + 32, schedule + 28, iteration);
            schedule[32] ^= schedule[0];
            schedule[33] ^= schedule[1];
            schedule[34] ^= schedule[2];
            schedule[35] ^= schedule[3];
            ++iteration;
            w = 0;
        } else if (w == 4) {
            // At the 16 byte mark we need to apply the S-box.
            applySbox(schedule + 32, schedule + 28);
            schedule[32] ^= schedule[0];
            schedule[33] ^= schedule[1];
            schedule[34] ^= schedule[2];
            schedule[35] ^= schedule[3];
        } else {
            // Otherwise just XOR the word with the one 32 bytes previous.
            schedule[32] = schedule[28] ^ schedule[0];
            schedule[33] = schedule[29] ^ schedule[1];
            schedule[34] = schedule[30] ^ schedule[2];
            schedule[35] = schedule[31] ^ schedule[3];
        }
        // Advance to the next word in the schedule.
        schedule += 4;
        n += 4;
        ++w;
    }
    return true;
}
/**
 * \class AESTiny256 AES.h <AES.h>
 * \brief AES block cipher with 256-bit keys and tiny memory usage.
 *
 * This class differs from the AES256 class in the following ways:
 *
 * \li RAM requirements are vastly reduced.  The key is stored directly
 * and then expanded to the full key schedule round by round.  The setKey()
 * method is very fast because of this.
 * \li Performance of encryptBlock() is slower than for AES256 due to
 * expanding the key on the fly rather than ahead of time.
 * \li The decryptBlock() function is not supported, which means that CBC
 * mode cannot be used but the CTR, CFB, OFB, EAX, and GCM modes can be used.
 *
 * This class is useful when RAM is at a premium, CBC mode is not required,
 * and reduced encryption performance is not a hindrance to the application.
 *
 * The companion AESSmall256 class supports decryptBlock() at the cost of
 * some additional memory and slower setKey() times.
 *
 * \sa AESSmall256, AES256
 */
/** @cond */
// Helper macros.
#define LEFT 0
#define RIGHT 16
#define ENCRYPT(phase) \
    do { \
        AESCommon::subBytesAndShiftRows(state2, state1); \
        AESCommon::mixColumn(state1,      state2); \
        AESCommon::mixColumn(state1 + 4,  state2 + 4); \
        AESCommon::mixColumn(state1 + 8,  state2 + 8); \
        AESCommon::mixColumn(state1 + 12, state2 + 12); \
        for (posn = 0; posn < 16; ++posn) \
            state1[posn] ^= schedule[posn + (phase)]; \
    } while (0)
#define DECRYPT(phase) \
    do { \
        for (posn = 0; posn < 16; ++posn) \
            state2[posn] ^= schedule[posn + (phase)]; \
        AESCommon::inverseMixColumn(state1,      state2); \
        AESCommon::inverseMixColumn(state1 + 4,  state2 + 4); \
        AESCommon::inverseMixColumn(state1 + 8,  state2 + 8); \
        AESCommon::inverseMixColumn(state1 + 12, state2 + 12); \
        AESCommon::inverseShiftRowsAndSubBytes(state2, state1); \
    } while (0)
#define KCORE(n) \
    do { \
        AESCommon::keyScheduleCore(temp, schedule + 28, (n)); \
        schedule[0] ^= temp[0]; \
        schedule[1] ^= temp[1]; \
        schedule[2] ^= temp[2]; \
        schedule[3] ^= temp[3]; \
    } while (0)
#define KXOR(a, b) \
    do { \
        schedule[(a) * 4] ^= schedule[(b) * 4]; \
        schedule[(a) * 4 + 1] ^= schedule[(b) * 4 + 1]; \
        schedule[(a) * 4 + 2] ^= schedule[(b) * 4 + 2]; \
        schedule[(a) * 4 + 3] ^= schedule[(b) * 4 + 3]; \
    } while (0)
#define KSBOX() \
    do { \
        AESCommon::applySbox(temp, schedule + 12); \
        schedule[16] ^= temp[0]; \
        schedule[17] ^= temp[1]; \
        schedule[18] ^= temp[2]; \
        schedule[19] ^= temp[3]; \
    } while (0)
/** @endcond */
/**
 * \brief Constructs an AES 256-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AESTiny256::AESTiny256()
{
}
AESTiny256::~AESTiny256()
{
    clean(schedule);
}
/**
 * \brief Size of an AES block in bytes.
 * \return Always returns 16.
 */
size_t AESTiny256::blockSize() const
{
    return 16;
}
/**
 * \brief Size of a 256-bit AES key in bytes.
 * \return Always returns 32.
 */
size_t AESTiny256::keySize() const
{
    return 32;
}
bool AESTiny256::setKey(const uint8_t *key, size_t len)
{
    if (len == 32) {
        // Make a copy of the key - it will be expanded in encryptBlock().
        memcpy(schedule, key, 32);
        return true;
    }
    return false;
}
void AESTiny256::encryptBlock(uint8_t *output, const uint8_t *input)
{
    uint8_t schedule[32];
    uint8_t posn;
    uint8_t round;
    uint8_t state1[16];
    uint8_t state2[16];
    uint8_t temp[4];
    // Start with the key in the schedule buffer.
    memcpy(schedule, this->schedule, 32);
    // Copy the input into the state and perform the first round.
    for (posn = 0; posn < 16; ++posn)
        state1[posn] = input[posn] ^ schedule[posn];
    ENCRYPT(RIGHT);
    // Perform the next 12 rounds of the cipher two at a time.
    for (round = 1; round <= 6; ++round) {
        // Expand the next 32 bytes of the key schedule.
        KCORE(round);
        KXOR(1, 0);
        KXOR(2, 1);
        KXOR(3, 2);
        KSBOX();
        KXOR(5, 4);
        KXOR(6, 5);
        KXOR(7, 6);
        // Encrypt using the left and right halves of the key schedule.
        ENCRYPT(LEFT);
        ENCRYPT(RIGHT);
    }
    // Expand the final 16 bytes of the key schedule.
    KCORE(7);
    KXOR(1, 0);
    KXOR(2, 1);
    KXOR(3, 2);
    // Perform the final round.
    AESCommon::subBytesAndShiftRows(state2, state1);
    for (posn = 0; posn < 16; ++posn)
        output[posn] = state2[posn] ^ schedule[posn];
}
void AESTiny256::decryptBlock(uint8_t *output, const uint8_t *input)
{
    // Decryption is not supported by AESTiny256.
}
void AESTiny256::clear()
{
    clean(schedule);
}
/**
 * \class AESSmall256 AES.h <AES.h>
 * \brief AES block cipher with 256-bit keys and reduced memory usage.
 *
 * This class differs from the AES256 class in that the RAM requirements are
 * vastly reduced.  The key schedule is expanded round by round instead of
 * being generated and stored by setKey().  The performance of encryption
 * and decryption is slightly less because of this.
 *
 * This class is useful when RAM is at a premium and reduced encryption
 * performance is not a hindrance to the application.
 *
 * The companion AESTiny256 class uses even less RAM but only supports the
 * encryptBlock() operation.  Block cipher modes like CTR, EAX, and GCM
 * do not need the decryptBlock() operation, so AESTiny256 may be a better
 * option than AESSmall256 for many applications.
 *
 * \sa AESTiny256, AES256
 */
/**
 * \brief Constructs an AES 256-bit block cipher with no initial key.
 *
 * This constructor must be followed by a call to setKey() before the
 * block cipher can be used for encryption or decryption.
 */
AESSmall256::AESSmall256()
{
}
AESSmall256::~AESSmall256()
{
    clean(reverse);
}
bool AESSmall256::setKey(const uint8_t *key, size_t len)
{
    uint8_t *schedule;
    uint8_t round;
    uint8_t temp[4];
    // Set the encryption key first.
    if (!AESTiny256::setKey(key, len))
        return false;
    // Expand the key schedule up to the last round which gives
    // us the round keys to use for the final two rounds.  We can
    // then work backwards from there in decryptBlock().
    schedule = reverse;
    memcpy(schedule, key, 32);
    for (round = 1; round <= 6; ++round) {
        KCORE(round);
        KXOR(1, 0);
        KXOR(2, 1);
        KXOR(3, 2);
        KSBOX();
        KXOR(5, 4);
        KXOR(6, 5);
        KXOR(7, 6);
    }
    KCORE(7);
    KXOR(1, 0);
    KXOR(2, 1);
    KXOR(3, 2);
    // Key is ready to go.
    return true;
}
void AESSmall256::decryptBlock(uint8_t *output, const uint8_t *input)
{
    uint8_t schedule[32];
    uint8_t round;
    uint8_t posn;
    uint8_t state1[16];
    uint8_t state2[16];
    uint8_t temp[4];
    // Start with the end of the decryption schedule.
    memcpy(schedule, reverse, 32);
    // Copy the input into the state and reverse the final round.
    for (posn = 0; posn < 16; ++posn)
        state1[posn] = input[posn] ^ schedule[posn];
    AESCommon::inverseShiftRowsAndSubBytes(state2, state1);
    KXOR(3, 2);
    KXOR(2, 1);
    KXOR(1, 0);
    KCORE(7);
    // Perform the next 12 rounds of the decryption process two at a time.
    for (round = 6; round >= 1; --round) {
        // Decrypt using the right and left halves of the key schedule.
        DECRYPT(RIGHT);
        DECRYPT(LEFT);
        // Expand the next 32 bytes of the key schedule in reverse.
        KXOR(7, 6);
        KXOR(6, 5);
        KXOR(5, 4);
        KSBOX();
        KXOR(3, 2);
        KXOR(2, 1);
        KXOR(1, 0);
        KCORE(round);
    }
    // Reverse the initial round and create the output words.
    DECRYPT(RIGHT);
    for (posn = 0; posn < 16; ++posn)
        output[posn] = state2[posn] ^ schedule[posn];
}
void AESSmall256::clear()
{
    clean(reverse);
    AESTiny256::clear();
}
#endif // CRYPTO_AES_DEFAULT
src/modules/Crypto/AESCommon.cpp
New file
@@ -0,0 +1,363 @@
/*
 * 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 "AES.h"
#include "Crypto.h"
#include "utility/ProgMemUtil.h"
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
/**
 * \class AESCommon AES.h <AES.h>
 * \brief Abstract base class for AES block ciphers.
 *
 * This class is abstract.  The caller should instantiate AES128,
 * AES192, or AES256 to create an AES block cipher with a specific
 * key size.
 *
 * \note This AES implementation does not have constant cache behaviour due
 * to the use of table lookups.  It may not be safe to use this implementation
 * in an environment where the attacker can observe the timing of encryption
 * and decryption operations.  Unless AES compatibility is required,
 * it is recommended that the ChaCha stream cipher be used instead.
 *
 * Reference: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
 *
 * \sa ChaCha, AES128, AES192, AES256
 */
/** @cond sbox */
// AES S-box (http://en.wikipedia.org/wiki/Rijndael_S-box)
static uint8_t const sbox[256] PROGMEM = {
    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,     // 0x00
    0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,     // 0x10
    0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,     // 0x20
    0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,     // 0x30
    0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,     // 0x40
    0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,     // 0x50
    0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,     // 0x60
    0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,     // 0x70
    0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,     // 0x80
    0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,     // 0x90
    0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,     // 0xA0
    0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,     // 0xB0
    0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,     // 0xC0
    0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,     // 0xD0
    0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,     // 0xE0
    0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,     // 0xF0
    0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
// AES inverse S-box (http://en.wikipedia.org/wiki/Rijndael_S-box)
static uint8_t const sbox_inverse[256] PROGMEM = {
    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,     // 0x00
    0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,     // 0x10
    0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,     // 0x20
    0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,     // 0x30
    0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,     // 0x40
    0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,     // 0x50
    0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
    0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,     // 0x60
    0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
    0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,     // 0x70
    0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
    0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,     // 0x80
    0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
    0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,     // 0x90
    0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
    0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,     // 0xA0
    0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
    0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,     // 0xB0
    0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
    0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,     // 0xC0
    0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
    0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,     // 0xD0
    0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
    0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,     // 0xE0
    0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
    0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,     // 0xF0
    0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
/** @endcond */
/**
 * \brief Constructs an AES block cipher object.
 */
AESCommon::AESCommon()
    : rounds(0), schedule(0)
{
}
/**
 * \brief Destroys this AES block cipher object after clearing
 * sensitive information.
 */
AESCommon::~AESCommon()
{
}
/**
 * \brief Size of an AES block in bytes.
 * \return Always returns 16.
 */
size_t AESCommon::blockSize() const
{
    return 16;
}
// Constants to correct Galois multiplication for the high bits
// that are shifted out when multiplying by powers of two.
static uint8_t const K[8] = {
    0x00,
    0x1B,
    (0x1B << 1),
    (0x1B << 1) ^ 0x1B,
    (0x1B << 2),
    (0x1B << 2) ^ 0x1B,
    (0x1B << 2) ^ (0x1B << 1),
    (0x1B << 2) ^ (0x1B << 1) ^ 0x1B
};
// Multiply x by 2 in the Galois field, to achieve the effect of the following:
//
//     if (x & 0x80)
//         return (x << 1) ^ 0x1B;
//     else
//         return (x << 1);
//
// However, we don't want to use runtime conditionals if we can help it
// to avoid leaking timing information from the implementation.
// In this case, multiplication is slightly faster than table lookup on AVR.
#define gmul2(x)    (t = ((uint16_t)(x)) << 1, \
                     ((uint8_t)t) ^ (uint8_t)(0x1B * ((uint8_t)(t >> 8))))
// Multiply x by 4 in the Galois field.
#define gmul4(x)    (t = ((uint16_t)(x)) << 2, ((uint8_t)t) ^ K[t >> 8])
// Multiply x by 8 in the Galois field.
#define gmul8(x)    (t = ((uint16_t)(x)) << 3, ((uint8_t)t) ^ K[t >> 8])
#define OUT(col, row)   output[(col) * 4 + (row)]
#define IN(col, row)    input[(col) * 4 + (row)]
/** @cond aes_funcs */
void AESCommon::subBytesAndShiftRows(uint8_t *output, const uint8_t *input)
{
    OUT(0, 0) = pgm_read_byte(sbox + IN(0, 0));
    OUT(0, 1) = pgm_read_byte(sbox + IN(1, 1));
    OUT(0, 2) = pgm_read_byte(sbox + IN(2, 2));
    OUT(0, 3) = pgm_read_byte(sbox + IN(3, 3));
    OUT(1, 0) = pgm_read_byte(sbox + IN(1, 0));
    OUT(1, 1) = pgm_read_byte(sbox + IN(2, 1));
    OUT(1, 2) = pgm_read_byte(sbox + IN(3, 2));
    OUT(1, 3) = pgm_read_byte(sbox + IN(0, 3));
    OUT(2, 0) = pgm_read_byte(sbox + IN(2, 0));
    OUT(2, 1) = pgm_read_byte(sbox + IN(3, 1));
    OUT(2, 2) = pgm_read_byte(sbox + IN(0, 2));
    OUT(2, 3) = pgm_read_byte(sbox + IN(1, 3));
    OUT(3, 0) = pgm_read_byte(sbox + IN(3, 0));
    OUT(3, 1) = pgm_read_byte(sbox + IN(0, 1));
    OUT(3, 2) = pgm_read_byte(sbox + IN(1, 2));
    OUT(3, 3) = pgm_read_byte(sbox + IN(2, 3));
}
void AESCommon::inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input)
{
    OUT(0, 0) = pgm_read_byte(sbox_inverse + IN(0, 0));
    OUT(0, 1) = pgm_read_byte(sbox_inverse + IN(3, 1));
    OUT(0, 2) = pgm_read_byte(sbox_inverse + IN(2, 2));
    OUT(0, 3) = pgm_read_byte(sbox_inverse + IN(1, 3));
    OUT(1, 0) = pgm_read_byte(sbox_inverse + IN(1, 0));
    OUT(1, 1) = pgm_read_byte(sbox_inverse + IN(0, 1));
    OUT(1, 2) = pgm_read_byte(sbox_inverse + IN(3, 2));
    OUT(1, 3) = pgm_read_byte(sbox_inverse + IN(2, 3));
    OUT(2, 0) = pgm_read_byte(sbox_inverse + IN(2, 0));
    OUT(2, 1) = pgm_read_byte(sbox_inverse + IN(1, 1));
    OUT(2, 2) = pgm_read_byte(sbox_inverse + IN(0, 2));
    OUT(2, 3) = pgm_read_byte(sbox_inverse + IN(3, 3));
    OUT(3, 0) = pgm_read_byte(sbox_inverse + IN(3, 0));
    OUT(3, 1) = pgm_read_byte(sbox_inverse + IN(2, 1));
    OUT(3, 2) = pgm_read_byte(sbox_inverse + IN(1, 2));
    OUT(3, 3) = pgm_read_byte(sbox_inverse + IN(0, 3));
}
void AESCommon::mixColumn(uint8_t *output, uint8_t *input)
{
    uint16_t t; // Needed by the gmul2 macro.
    uint8_t a = input[0];
    uint8_t b = input[1];
    uint8_t c = input[2];
    uint8_t d = input[3];
    uint8_t a2 = gmul2(a);
    uint8_t b2 = gmul2(b);
    uint8_t c2 = gmul2(c);
    uint8_t d2 = gmul2(d);
    output[0] = a2 ^ b2 ^ b ^ c ^ d;
    output[1] = a ^ b2 ^ c2 ^ c ^ d;
    output[2] = a ^ b ^ c2 ^ d2 ^ d;
    output[3] = a2 ^ a ^ b ^ c ^ d2;
}
void AESCommon::inverseMixColumn(uint8_t *output, const uint8_t *input)
{
    uint16_t t; // Needed by the gmul2, gmul4, and gmul8 macros.
    uint8_t a = input[0];
    uint8_t b = input[1];
    uint8_t c = input[2];
    uint8_t d = input[3];
    uint8_t a2 = gmul2(a);
    uint8_t b2 = gmul2(b);
    uint8_t c2 = gmul2(c);
    uint8_t d2 = gmul2(d);
    uint8_t a4 = gmul4(a);
    uint8_t b4 = gmul4(b);
    uint8_t c4 = gmul4(c);
    uint8_t d4 = gmul4(d);
    uint8_t a8 = gmul8(a);
    uint8_t b8 = gmul8(b);
    uint8_t c8 = gmul8(c);
    uint8_t d8 = gmul8(d);
    output[0] = a8 ^ a4 ^ a2 ^ b8 ^ b2 ^ b ^ c8 ^ c4 ^ c ^ d8 ^ d;
    output[1] = a8 ^ a ^ b8 ^ b4 ^ b2 ^ c8 ^ c2 ^ c ^ d8 ^ d4 ^ d;
    output[2] = a8 ^ a4 ^ a ^ b8 ^ b ^ c8 ^ c4 ^ c2 ^ d8 ^ d2 ^ d;
    output[3] = a8 ^ a2 ^ a ^ b8 ^ b4 ^ b ^ c8 ^ c ^ d8 ^ d4 ^ d2;
}
/** @endcond */
void AESCommon::encryptBlock(uint8_t *output, const uint8_t *input)
{
    const uint8_t *roundKey = schedule;
    uint8_t posn;
    uint8_t round;
    uint8_t state1[16];
    uint8_t state2[16];
    // Copy the input into the state and XOR with the first round key.
    for (posn = 0; posn < 16; ++posn)
        state1[posn] = input[posn] ^ roundKey[posn];
    roundKey += 16;
    // Perform all rounds except the last.
    for (round = rounds; round > 1; --round) {
        subBytesAndShiftRows(state2, state1);
        mixColumn(state1,      state2);
        mixColumn(state1 + 4,  state2 + 4);
        mixColumn(state1 + 8,  state2 + 8);
        mixColumn(state1 + 12, state2 + 12);
        for (posn = 0; posn < 16; ++posn)
            state1[posn] ^= roundKey[posn];
        roundKey += 16;
    }
    // Perform the final round.
    subBytesAndShiftRows(state2, state1);
    for (posn = 0; posn < 16; ++posn)
        output[posn] = state2[posn] ^ roundKey[posn];
}
void AESCommon::decryptBlock(uint8_t *output, const uint8_t *input)
{
    const uint8_t *roundKey = schedule + rounds * 16;
    uint8_t round;
    uint8_t posn;
    uint8_t state1[16];
    uint8_t state2[16];
    // Copy the input into the state and reverse the final round.
    for (posn = 0; posn < 16; ++posn)
        state1[posn] = input[posn] ^ roundKey[posn];
    inverseShiftRowsAndSubBytes(state2, state1);
    // Perform all other rounds in reverse.
    for (round = rounds; round > 1; --round) {
        roundKey -= 16;
        for (posn = 0; posn < 16; ++posn)
            state2[posn] ^= roundKey[posn];
        inverseMixColumn(state1,      state2);
        inverseMixColumn(state1 + 4,  state2 + 4);
        inverseMixColumn(state1 + 8,  state2 + 8);
        inverseMixColumn(state1 + 12, state2 + 12);
        inverseShiftRowsAndSubBytes(state2, state1);
    }
    // Reverse the initial round and create the output words.
    roundKey -= 16;
    for (posn = 0; posn < 16; ++posn)
        output[posn] = state2[posn] ^ roundKey[posn];
}
void AESCommon::clear()
{
    clean(schedule, (rounds + 1) * 16);
}
/** @cond aes_keycore */
void AESCommon::keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration)
{
    // Rcon(i), 2^i in the Rijndael finite field, for i = 0..10.
    // http://en.wikipedia.org/wiki/Rijndael_key_schedule
    static uint8_t const rcon[11] PROGMEM = {
        0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,     // 0x00
        0x80, 0x1B, 0x36
    };
    output[0] = pgm_read_byte(sbox + input[1]) ^ pgm_read_byte(rcon + iteration);
    output[1] = pgm_read_byte(sbox + input[2]);
    output[2] = pgm_read_byte(sbox + input[3]);
    output[3] = pgm_read_byte(sbox + input[0]);
}
void AESCommon::applySbox(uint8_t *output, const uint8_t *input)
{
    output[0] = pgm_read_byte(sbox + input[0]);
    output[1] = pgm_read_byte(sbox + input[1]);
    output[2] = pgm_read_byte(sbox + input[2]);
    output[3] = pgm_read_byte(sbox + input[3]);
}
/** @endcond */
#endif // CRYPTO_AES_DEFAULT
src/modules/Crypto/AESEsp32.cpp
New file
@@ -0,0 +1,88 @@
/*
 * Copyright (C) 2018 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 "AES.h"
#include "Crypto.h"
#include <string.h>
// AES implementation for ESP32 using the hardware crypto module.
#if defined(CRYPTO_AES_ESP32)
AESCommon::AESCommon(uint8_t keySize)
{
    ctx.key_bytes = keySize;
}
AESCommon::~AESCommon()
{
    clean(ctx.key, sizeof(ctx.key));
}
size_t AESCommon::blockSize() const
{
    return 16;
}
size_t AESCommon::keySize() const
{
    return ctx.key_bytes;
}
bool AESCommon::setKey(const uint8_t *key, size_t len)
{
    if (len == ctx.key_bytes) {
        // Do the effect of esp_aes_setkey() which is just a memcpy().
        memcpy(ctx.key, key, len);
        return true;
    }
    return false;
}
void AESCommon::encryptBlock(uint8_t *output, const uint8_t *input)
{
    esp_aes_encrypt(&ctx, input, output);
}
void AESCommon::decryptBlock(uint8_t *output, const uint8_t *input)
{
    esp_aes_decrypt(&ctx, input, output);
}
void AESCommon::clear()
{
    clean(ctx.key, sizeof(ctx.key));
}
AES128::~AES128()
{
}
AES192::~AES192()
{
}
AES256::~AES256()
{
}
#endif // CRYPTO_AES_ESP32
src/modules/Crypto/AuthenticatedCipher.cpp
New file
@@ -0,0 +1,130 @@
/*
 * 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 "AuthenticatedCipher.h"
/**
 * \class AuthenticatedCipher AuthenticatedCipher.h <AuthenticatedCipher.h>
 * \brief Abstract base class for authenticated ciphers.
 *
 * This class abstracts the details of algorithms that provide Authenticated
 * Encryption with Associated Data (AEAD).  Such algorithms combine
 * encryption with message authentication to provide a single primitive.
 *
 * Authenticated ciphers have four parameters: the secret key, an
 * initialization vector (called a "nonce" in the literature), the
 * plaintext, and some associated data which is to be authenticated
 * with the plaintext but not encrypted.  Associated data might be
 * sequence numbers, IP addresses, protocol versions, or other information
 * that is not secret but is important and unique to the session.
 *
 * Subclasses encrypt the plaintext content and output the ciphertext.
 * Once all plaintext has been processed, the caller should invoke
 * computeTag() to obtain the authentication tag to transmit with
 * the ciphertext.  When the ciphertext is later decrypted, the checkTag()
 * function can be used to check that the data is authentic.
 *
 * Reference: <a href="http://tools.ietf.org/html/rfc5116">RFC 5116</a>
 *
 * \sa Cipher
 */
/**
 * \brief Constructs a new authenticated cipher.
 */
AuthenticatedCipher::AuthenticatedCipher()
{
}
/**
 * \brief Destroys this authenticated cipher.
 */
AuthenticatedCipher::~AuthenticatedCipher()
{
}
/**
 * \fn size_t AuthenticatedCipher::tagSize() const
 * \brief Returns the size of the authentication tag.
 *
 * \return The size of the authentication tag in bytes.
 *
 * By default this function should return the largest tag size supported
 * by the authenticated cipher.
 *
 * \sa computeTag()
 */
/**
 * \fn void AuthenticatedCipher::addAuthData(const void *data, size_t len)
 * \brief Adds extra data that will be authenticated but not encrypted.
 *
 * \param data The extra data to be authenticated.
 * \param len The number of bytes of extra data to be authenticated.
 *
 * This function must be called before the first call to encrypt() or
 * decrypt().  That is, it is assumed that all extra data for authentication
 * is available before the first payload data block and that it will be
 * prepended to the payload for authentication.  If the subclass needs to
 * process the extra data after the payload, then it is responsible for saving
 * \a data away until it is needed during computeTag() or checkTag().
 *
 * This function can be called multiple times with separate extra data
 * blocks for authentication.  All such data will be concatenated into a
 * single block for authentication purposes.
 */
/**
 * \fn void AuthenticatedCipher::computeTag(void *tag, size_t len)
 * \brief Finalizes the encryption process and computes the authentication tag.
 *
 * \param tag Points to the buffer to write the tag to.
 * \param len The length of the tag, which may be less than tagSize() to
 * truncate the tag to the first \a len bytes.
 *
 * \sa checkTag()
 */
/**
 * \fn bool AuthenticatedCipher::checkTag(const void *tag, size_t len)
 * \brief Finalizes the decryption process and checks the authentication tag.
 *
 * \param tag The tag value from the incoming ciphertext to be checked.
 * \param len The length of the tag value in bytes, which may be less
 * than tagSize().
 *
 * \return Returns true if the \a tag is identical to the first \a len
 * bytes of the authentication tag that was calculated during the
 * decryption process.  Returns false otherwise.
 *
 * This function must be called after the final block of ciphertext is
 * passed to decrypt() to determine if the data could be authenticated.
 *
 * \note Authenticated cipher modes usually require that if the tag could
 * not be verified, then all of the data that was previously decrypted
 * <i>must</i> be discarded.  It is unwise to use the decrypted data for
 * any purpose before it can be verified.  Callers are responsible for
 * ensuring that any data returned via previous calls to decrypt() is
 * discarded if checkTag() returns false.
 *
 * \sa computeTag()
 */
src/modules/Crypto/AuthenticatedCipher.h
New file
@@ -0,0 +1,42 @@
/*
 * 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.
 */
#ifndef CRYPTO_AUTHENTICATEDCIPHER_h
#define CRYPTO_AUTHENTICATEDCIPHER_h
#include "Cipher.h"
class AuthenticatedCipher : public Cipher
{
public:
    AuthenticatedCipher();
    virtual ~AuthenticatedCipher();
    virtual size_t tagSize() const = 0;
    virtual void addAuthData(const void *data, size_t len) = 0;
    virtual void computeTag(void *tag, size_t len) = 0;
    virtual bool checkTag(const void *tag, size_t len) = 0;
};
#endif
src/modules/Crypto/BLAKE2b.cpp
New file
@@ -0,0 +1,330 @@
/*
 * 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 "BLAKE2b.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include "utility/RotateUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
 * \class BLAKE2b BLAKE2b.h <BLAKE2b.h>
 * \brief BLAKE2b hash algorithm.
 *
 * BLAKE2b is a variation on the ChaCha stream cipher, designed for hashing,
 * with a 512-bit hash output.  It is intended as a high performance
 * replacement for SHA512 for when speed is critical but exact SHA512
 * compatibility is not.
 *
 * This class supports two types of keyed hash.  The BLAKE2 keyed hash and
 * traditional HMAC.  The BLAKE2 keyed hash is recommended unless there is
 * some higher-level application need to be compatible with the HMAC
 * construction.  The keyed hash is computed as follows:
 *
 * \code
 * BLAKE2b blake;
 * blake.reset(key, sizeof(key), outputLength);
 * blake.update(data1, sizeof(data1));
 * blake.update(data2, sizeof(data2));
 * ...
 * blake.update(dataN, sizeof(dataN));
 * blake.finalize(hash, outputLength);
 * \endcode
 *
 * The HMAC is computed as follows (the output length is always 64):
 *
 * \code
 * BLAKE2b blake;
 * blake.resetHMAC(key, sizeof(key));
 * blake.update(data1, sizeof(data1));
 * blake.update(data2, sizeof(data2));
 * ...
 * blake.update(dataN, sizeof(dataN));
 * blake.finalizeHMAC(key, sizeof(key), hash, 32);
 * \endcode
 *
 * References: https://blake2.net/,
 * <a href="http://tools.ietf.org/html/rfc7693">RFC 7693</a>
 *
 * \sa BLAKE2s, SHA512, SHA3_512
 */
/**
 * \brief Constructs a BLAKE2b hash object.
 */
BLAKE2b::BLAKE2b()
{
    reset();
}
/**
 * \brief Destroys this BLAKE2b hash object after clearing
 * sensitive information.
 */
BLAKE2b::~BLAKE2b()
{
    clean(state);
}
size_t BLAKE2b::hashSize() const
{
    return 64;
}
size_t BLAKE2b::blockSize() const
{
    return 128;
}
// Initialization vectors for BLAKE2b.
#define BLAKE2b_IV0 0x6a09e667f3bcc908ULL
#define BLAKE2b_IV1 0xbb67ae8584caa73bULL
#define BLAKE2b_IV2 0x3c6ef372fe94f82bULL
#define BLAKE2b_IV3 0xa54ff53a5f1d36f1ULL
#define BLAKE2b_IV4 0x510e527fade682d1ULL
#define BLAKE2b_IV5 0x9b05688c2b3e6c1fULL
#define BLAKE2b_IV6 0x1f83d9abfb41bd6bULL
#define BLAKE2b_IV7 0x5be0cd19137e2179ULL
void BLAKE2b::reset()
{
    state.h[0] = BLAKE2b_IV0 ^ 0x01010040; // Default output length of 64.
    state.h[1] = BLAKE2b_IV1;
    state.h[2] = BLAKE2b_IV2;
    state.h[3] = BLAKE2b_IV3;
    state.h[4] = BLAKE2b_IV4;
    state.h[5] = BLAKE2b_IV5;
    state.h[6] = BLAKE2b_IV6;
    state.h[7] = BLAKE2b_IV7;
    state.chunkSize = 0;
    state.lengthLow = 0;
    state.lengthHigh = 0;
}
/**
 * \brief Resets the hash ready for a new hashing process with a specified
 * output length.
 *
 * \param outputLength The output length to use for the final hash in bytes,
 * between 1 and 64.
 */
void BLAKE2b::reset(uint8_t outputLength)
{
    if (outputLength < 1)
        outputLength = 1;
    else if (outputLength > 64)
        outputLength = 64;
    state.h[0] = BLAKE2b_IV0 ^ 0x01010000 ^ outputLength;
    state.h[1] = BLAKE2b_IV1;
    state.h[2] = BLAKE2b_IV2;
    state.h[3] = BLAKE2b_IV3;
    state.h[4] = BLAKE2b_IV4;
    state.h[5] = BLAKE2b_IV5;
    state.h[6] = BLAKE2b_IV6;
    state.h[7] = BLAKE2b_IV7;
    state.chunkSize = 0;
    state.lengthLow = 0;
    state.lengthHigh = 0;
}
/**
 * \brief Resets the hash ready for a new hashing process with a specified
 * key and output length.
 *
 * \param key Points to the key.
 * \param keyLen The length of the key in bytes, between 0 and 64.
 * \param outputLength The output length to use for the final hash in bytes,
 * between 1 and 64.
 *
 * If \a keyLen is greater than 64, then the \a key will be truncated to
 * the first 64 bytes.
 */
void BLAKE2b::reset(const void *key, size_t keyLen, uint8_t outputLength)
{
    if (keyLen > 64)
        keyLen = 64;
    if (outputLength < 1)
        outputLength = 1;
    else if (outputLength > 64)
        outputLength = 64;
    state.h[0] = BLAKE2b_IV0 ^ 0x01010000 ^ (keyLen << 8) ^ outputLength;
    state.h[1] = BLAKE2b_IV1;
    state.h[2] = BLAKE2b_IV2;
    state.h[3] = BLAKE2b_IV3;
    state.h[4] = BLAKE2b_IV4;
    state.h[5] = BLAKE2b_IV5;
    state.h[6] = BLAKE2b_IV6;
    state.h[7] = BLAKE2b_IV7;
    if (keyLen > 0) {
        // Set the first block to the key and pad with zeroes.
        memcpy(state.m, key, keyLen);
        memset(((uint8_t *)state.m) + keyLen, 0, 128 - keyLen);
        state.chunkSize = 128;
        state.lengthLow = 128;
    } else {
        // No key.  The first data block is the first hashed block.
        state.chunkSize = 0;
        state.lengthLow = 0;
    }
    state.lengthHigh = 0;
}
void BLAKE2b::update(const void *data, size_t len)
{
    // Break the input up into 1024-bit chunks and process each in turn.
    const uint8_t *d = (const uint8_t *)data;
    while (len > 0) {
        if (state.chunkSize == 128) {
            // Previous chunk was full and we know that it wasn't the
            // last chunk, so we can process it now with f0 set to zero.
            processChunk(0);
            state.chunkSize = 0;
        }
        uint8_t size = 128 - state.chunkSize;
        if (size > len)
            size = len;
        memcpy(((uint8_t *)state.m) + state.chunkSize, d, size);
        state.chunkSize += size;
        uint64_t temp = state.lengthLow;
        state.lengthLow += size;
        if (state.lengthLow < temp)
            ++state.lengthHigh;
        len -= size;
        d += size;
    }
}
void BLAKE2b::finalize(void *hash, size_t len)
{
    // Pad the last chunk and hash it with f0 set to all-ones.
    memset(((uint8_t *)state.m) + state.chunkSize, 0, 128 - state.chunkSize);
    processChunk(0xFFFFFFFFFFFFFFFFULL);
    // Convert the hash into little-endian in the message buffer.
    for (uint8_t posn = 0; posn < 8; ++posn)
        state.m[posn] = htole64(state.h[posn]);
    // Copy the hash to the caller's return buffer.
    if (len > 64)
        len = 64;
    memcpy(hash, state.m, len);
}
void BLAKE2b::clear()
{
    clean(state);
    reset();
}
void BLAKE2b::resetHMAC(const void *key, size_t keyLen)
{
    formatHMACKey(state.m, key, keyLen, 0x36);
    state.lengthLow += 128;
    processChunk(0);
}
void BLAKE2b::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
    uint8_t temp[64];
    finalize(temp, sizeof(temp));
    formatHMACKey(state.m, key, keyLen, 0x5C);
    state.lengthLow += 128;
    processChunk(0);
    update(temp, sizeof(temp));
    finalize(hash, hashLen);
    clean(temp);
}
// Permutation on the message input state for BLAKE2b.
static const uint8_t sigma[12][16] PROGMEM = {
    { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15},
    {14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3},
    {11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4},
    { 7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8},
    { 9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13},
    { 2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9},
    {12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11},
    {13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10},
    { 6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5},
    {10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0},
    { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15},
    {14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3},
};
// Perform a BLAKE2b quarter round operation.
#define quarterRound(a, b, c, d, i)    \
    do { \
        uint64_t _b = (b); \
        uint64_t _a = (a) + _b + state.m[pgm_read_byte(&(sigma[index][2 * (i)]))]; \
        uint64_t _d = rightRotate32_64((d) ^ _a); \
        uint64_t _c = (c) + _d; \
        _b = rightRotate24_64(_b ^ _c); \
        _a += _b + state.m[pgm_read_byte(&(sigma[index][2 * (i) + 1]))]; \
        (d) = _d = rightRotate16_64(_d ^ _a); \
        _c += _d; \
        (a) = _a; \
        (b) = rightRotate63_64(_b ^ _c); \
        (c) = _c; \
    } while (0)
void BLAKE2b::processChunk(uint64_t f0)
{
    uint8_t index;
    uint64_t v[16];
    // Byte-swap the message buffer into little-endian if necessary.
#if !defined(CRYPTO_LITTLE_ENDIAN)
    for (index = 0; index < 16; ++index)
        state.m[index] = le64toh(state.m[index]);
#endif
    // Format the block to be hashed.
    memcpy(v, state.h, sizeof(state.h));
    v[8]  = BLAKE2b_IV0;
    v[9]  = BLAKE2b_IV1;
    v[10] = BLAKE2b_IV2;
    v[11] = BLAKE2b_IV3;
    v[12] = BLAKE2b_IV4 ^ state.lengthLow;
    v[13] = BLAKE2b_IV5 ^ state.lengthHigh;
    v[14] = BLAKE2b_IV6 ^ f0;
    v[15] = BLAKE2b_IV7;
    // Perform the 12 BLAKE2b rounds.
    for (index = 0; index < 12; ++index) {
        // Column round.
        quarterRound(v[0], v[4], v[8],  v[12], 0);
        quarterRound(v[1], v[5], v[9],  v[13], 1);
        quarterRound(v[2], v[6], v[10], v[14], 2);
        quarterRound(v[3], v[7], v[11], v[15], 3);
        // Diagonal round.
        quarterRound(v[0], v[5], v[10], v[15], 4);
        quarterRound(v[1], v[6], v[11], v[12], 5);
        quarterRound(v[2], v[7], v[8],  v[13], 6);
        quarterRound(v[3], v[4], v[9],  v[14], 7);
    }
    // Combine the new and old hash values.
    for (index = 0; index < 8; ++index)
        state.h[index] ^= (v[index] ^ v[index + 8]);
}
src/modules/Crypto/BLAKE2b.h
New file
@@ -0,0 +1,61 @@
/*
 * 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.
 */
#ifndef CRYPTO_BLAKE2B_H
#define CRYPTO_BLAKE2B_H
#include "Hash.h"
class BLAKE2b : public Hash
{
public:
    BLAKE2b();
    virtual ~BLAKE2b();
    size_t hashSize() const;
    size_t blockSize() const;
    void reset();
    void reset(uint8_t outputLength);
    void reset(const void *key, size_t keyLen, uint8_t outputLength = 64);
    void update(const void *data, size_t len);
    void finalize(void *hash, size_t len);
    void clear();
    void resetHMAC(const void *key, size_t keyLen);
    void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
private:
    struct {
        uint64_t h[8];
        uint64_t m[16];
        uint64_t lengthLow;
        uint64_t lengthHigh;
        uint8_t chunkSize;
    } state;
    void processChunk(uint64_t f0);
};
#endif
src/modules/Crypto/BLAKE2s.cpp
New file
@@ -0,0 +1,322 @@
/*
 * 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 "BLAKE2s.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include "utility/RotateUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
 * \class BLAKE2s BLAKE2s.h <BLAKE2s.h>
 * \brief BLAKE2s hash algorithm.
 *
 * BLAKE2s is a variation on the ChaCha stream cipher, designed for hashing,
 * with a 256-bit hash output.  It is intended as a high performance
 * replacement for SHA256 for when speed is critical but exact SHA256
 * compatibility is not.
 *
 * This class supports two types of keyed hash.  The BLAKE2 keyed hash and
 * traditional HMAC.  The BLAKE2 keyed hash is recommended unless there is
 * some higher-level application need to be compatible with the HMAC
 * construction.  The keyed hash is computed as follows:
 *
 * \code
 * BLAKE2s blake;
 * blake.reset(key, sizeof(key), outputLength);
 * blake.update(data1, sizeof(data1));
 * blake.update(data2, sizeof(data2));
 * ...
 * blake.update(dataN, sizeof(dataN));
 * blake.finalize(hash, outputLength);
 * \endcode
 *
 * The HMAC is computed as follows (the output length is always 32):
 *
 * \code
 * BLAKE2s blake;
 * blake.resetHMAC(key, sizeof(key));
 * blake.update(data1, sizeof(data1));
 * blake.update(data2, sizeof(data2));
 * ...
 * blake.update(dataN, sizeof(dataN));
 * blake.finalizeHMAC(key, sizeof(key), hash, 32);
 * \endcode
 *
 * References: https://blake2.net/,
 * <a href="http://tools.ietf.org/html/rfc7693">RFC 7693</a>
 *
 * \sa BLAKE2b, SHA256, SHA3_256
 */
/**
 * \brief Constructs a BLAKE2s hash object.
 */
BLAKE2s::BLAKE2s()
{
    reset();
}
/**
 * \brief Destroys this BLAKE2s hash object after clearing
 * sensitive information.
 */
BLAKE2s::~BLAKE2s()
{
    clean(state);
}
size_t BLAKE2s::hashSize() const
{
    return 32;
}
size_t BLAKE2s::blockSize() const
{
    return 64;
}
// Initialization vectors for BLAKE2s.
#define BLAKE2s_IV0 0x6A09E667
#define BLAKE2s_IV1 0xBB67AE85
#define BLAKE2s_IV2 0x3C6EF372
#define BLAKE2s_IV3 0xA54FF53A
#define BLAKE2s_IV4 0x510E527F
#define BLAKE2s_IV5 0x9B05688C
#define BLAKE2s_IV6 0x1F83D9AB
#define BLAKE2s_IV7 0x5BE0CD19
void BLAKE2s::reset()
{
    state.h[0] = BLAKE2s_IV0 ^ 0x01010020; // Default output length of 32.
    state.h[1] = BLAKE2s_IV1;
    state.h[2] = BLAKE2s_IV2;
    state.h[3] = BLAKE2s_IV3;
    state.h[4] = BLAKE2s_IV4;
    state.h[5] = BLAKE2s_IV5;
    state.h[6] = BLAKE2s_IV6;
    state.h[7] = BLAKE2s_IV7;
    state.chunkSize = 0;
    state.length = 0;
}
/**
 * \brief Resets the hash ready for a new hashing process with a specified
 * output length.
 *
 * \param outputLength The output length to use for the final hash in bytes,
 * between 1 and 32.
 */
void BLAKE2s::reset(uint8_t outputLength)
{
    if (outputLength < 1)
        outputLength = 1;
    else if (outputLength > 32)
        outputLength = 32;
    state.h[0] = BLAKE2s_IV0 ^ 0x01010000 ^ outputLength;
    state.h[1] = BLAKE2s_IV1;
    state.h[2] = BLAKE2s_IV2;
    state.h[3] = BLAKE2s_IV3;
    state.h[4] = BLAKE2s_IV4;
    state.h[5] = BLAKE2s_IV5;
    state.h[6] = BLAKE2s_IV6;
    state.h[7] = BLAKE2s_IV7;
    state.chunkSize = 0;
    state.length = 0;
}
/**
 * \brief Resets the hash ready for a new hashing process with a specified
 * key and output length.
 *
 * \param key Points to the key.
 * \param keyLen The length of the key in bytes, between 0 and 32.
 * \param outputLength The output length to use for the final hash in bytes,
 * between 1 and 32.
 *
 * If \a keyLen is greater than 32, then the \a key will be truncated to
 * the first 32 bytes.
 */
void BLAKE2s::reset(const void *key, size_t keyLen, uint8_t outputLength)
{
    if (keyLen > 32)
        keyLen = 32;
    if (outputLength < 1)
        outputLength = 1;
    else if (outputLength > 32)
        outputLength = 32;
    state.h[0] = BLAKE2s_IV0 ^ 0x01010000 ^ (keyLen << 8) ^ outputLength;
    state.h[1] = BLAKE2s_IV1;
    state.h[2] = BLAKE2s_IV2;
    state.h[3] = BLAKE2s_IV3;
    state.h[4] = BLAKE2s_IV4;
    state.h[5] = BLAKE2s_IV5;
    state.h[6] = BLAKE2s_IV6;
    state.h[7] = BLAKE2s_IV7;
    if (keyLen > 0) {
        // Set the first block to the key and pad with zeroes.
        memcpy(state.m, key, keyLen);
        memset(((uint8_t *)state.m) + keyLen, 0, 64 - keyLen);
        state.chunkSize = 64;
        state.length = 64;
    } else {
        // No key.  The first data block is the first hashed block.
        state.chunkSize = 0;
        state.length = 0;
    }
}
void BLAKE2s::update(const void *data, size_t len)
{
    // Break the input up into 512-bit chunks and process each in turn.
    const uint8_t *d = (const uint8_t *)data;
    while (len > 0) {
        if (state.chunkSize == 64) {
            // Previous chunk was full and we know that it wasn't the
            // last chunk, so we can process it now with f0 set to zero.
            processChunk(0);
            state.chunkSize = 0;
        }
        uint8_t size = 64 - state.chunkSize;
        if (size > len)
            size = len;
        memcpy(((uint8_t *)state.m) + state.chunkSize, d, size);
        state.chunkSize += size;
        state.length += size;
        len -= size;
        d += size;
    }
}
void BLAKE2s::finalize(void *hash, size_t len)
{
    // Pad the last chunk and hash it with f0 set to all-ones.
    memset(((uint8_t *)state.m) + state.chunkSize, 0, 64 - state.chunkSize);
    processChunk(0xFFFFFFFF);
    // Convert the hash into little-endian in the message buffer.
    for (uint8_t posn = 0; posn < 8; ++posn)
        state.m[posn] = htole32(state.h[posn]);
    // Copy the hash to the caller's return buffer.
    if (len > 32)
        len = 32;
    memcpy(hash, state.m, len);
}
void BLAKE2s::clear()
{
    clean(state);
    reset();
}
void BLAKE2s::resetHMAC(const void *key, size_t keyLen)
{
    formatHMACKey(state.m, key, keyLen, 0x36);
    state.length += 64;
    processChunk(0);
}
void BLAKE2s::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
    uint8_t temp[32];
    finalize(temp, sizeof(temp));
    formatHMACKey(state.m, key, keyLen, 0x5C);
    state.length += 64;
    processChunk(0);
    update(temp, sizeof(temp));
    finalize(hash, hashLen);
    clean(temp);
}
// Permutation on the message input state for BLAKE2s.
static const uint8_t sigma[10][16] PROGMEM = {
    { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15},
    {14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3},
    {11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4},
    { 7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8},
    { 9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13},
    { 2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9},
    {12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11},
    {13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10},
    { 6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5},
    {10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0}
};
// Perform a BLAKE2s quarter round operation.
#define quarterRound(a, b, c, d, i)    \
    do { \
        uint32_t _b = (b); \
        uint32_t _a = (a) + _b + state.m[pgm_read_byte(&(sigma[index][2 * (i)]))]; \
        uint32_t _d = rightRotate16((d) ^ _a); \
        uint32_t _c = (c) + _d; \
        _b = rightRotate12(_b ^ _c); \
        _a += _b + state.m[pgm_read_byte(&(sigma[index][2 * (i) + 1]))]; \
        (d) = _d = rightRotate8(_d ^ _a); \
        _c += _d; \
        (a) = _a; \
        (b) = rightRotate7(_b ^ _c); \
        (c) = _c; \
    } while (0)
void BLAKE2s::processChunk(uint32_t f0)
{
    uint8_t index;
    uint32_t v[16];
    // Byte-swap the message buffer into little-endian if necessary.
#if !defined(CRYPTO_LITTLE_ENDIAN)
    for (index = 0; index < 16; ++index)
        state.m[index] = le32toh(state.m[index]);
#endif
    // Format the block to be hashed.
    memcpy(v, state.h, sizeof(state.h));
    v[8]  = BLAKE2s_IV0;
    v[9]  = BLAKE2s_IV1;
    v[10] = BLAKE2s_IV2;
    v[11] = BLAKE2s_IV3;
    v[12] = BLAKE2s_IV4 ^ (uint32_t)(state.length);
    v[13] = BLAKE2s_IV5 ^ (uint32_t)(state.length >> 32);
    v[14] = BLAKE2s_IV6 ^ f0;
    v[15] = BLAKE2s_IV7;
    // Perform the 10 BLAKE2s rounds.
    for (index = 0; index < 10; ++index) {
        // Column round.
        quarterRound(v[0], v[4], v[8],  v[12], 0);
        quarterRound(v[1], v[5], v[9],  v[13], 1);
        quarterRound(v[2], v[6], v[10], v[14], 2);
        quarterRound(v[3], v[7], v[11], v[15], 3);
        // Diagonal round.
        quarterRound(v[0], v[5], v[10], v[15], 4);
        quarterRound(v[1], v[6], v[11], v[12], 5);
        quarterRound(v[2], v[7], v[8],  v[13], 6);
        quarterRound(v[3], v[4], v[9],  v[14], 7);
    }
    // Combine the new and old hash values.
    for (index = 0; index < 8; ++index)
        state.h[index] ^= (v[index] ^ v[index + 8]);
}
src/modules/Crypto/BLAKE2s.h
New file
@@ -0,0 +1,60 @@
/*
 * 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.
 */
#ifndef CRYPTO_BLAKE2S_H
#define CRYPTO_BLAKE2S_H
#include "Hash.h"
class BLAKE2s : public Hash
{
public:
    BLAKE2s();
    virtual ~BLAKE2s();
    size_t hashSize() const;
    size_t blockSize() const;
    void reset();
    void reset(uint8_t outputLength);
    void reset(const void *key, size_t keyLen, uint8_t outputLength = 32);
    void update(const void *data, size_t len);
    void finalize(void *hash, size_t len);
    void clear();
    void resetHMAC(const void *key, size_t keyLen);
    void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
private:
    struct {
        uint32_t h[8];
        uint32_t m[16];
        uint64_t length;
        uint8_t chunkSize;
    } state;
    void processChunk(uint32_t f0);
};
#endif
src/modules/Crypto/BigNumberUtil.cpp
New file
@@ -0,0 +1,769 @@
/*
 * 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 "BigNumberUtil.h"
#include "utility/EndianUtil.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
 * \class BigNumberUtil BigNumberUtil.h <BigNumberUtil.h>
 * \brief Utilities to assist with implementing big number arithmetic.
 *
 * Big numbers are represented as arrays of limb_t words, which may be
 * 8 bits, 16 bits, or 32 bits in size depending upon how the library
 * was configured.  For AVR, 16 bit limbs usually give the best performance.
 *
 * Limb arrays are ordered from the least significant word to the most
 * significant.
 */
/**
 * \brief Unpacks the little-endian byte representation of a big number
 * into a limb array.
 *
 * \param limbs The limb array, starting with the least significant word.
 * \param count The number of elements in the \a limbs array.
 * \param bytes The bytes to unpack.
 * \param len The number of bytes to unpack.
 *
 * If \a len is shorter than the length of \a limbs, then the high bytes
 * will be filled with zeroes.  If \a len is longer than the length of
 * \a limbs, then the high bytes will be truncated and lost.
 *
 * \sa packLE(), unpackBE()
 */
void BigNumberUtil::unpackLE(limb_t *limbs, size_t count,
                             const uint8_t *bytes, size_t len)
{
#if BIGNUMBER_LIMB_8BIT
    if (len < count) {
        memcpy(limbs, bytes, len);
        memset(limbs + len, 0, count - len);
    } else {
        memcpy(limbs, bytes, count);
    }
#elif CRYPTO_LITTLE_ENDIAN
    count *= sizeof(limb_t);
    if (len < count) {
        memcpy(limbs, bytes, len);
        memset(((uint8_t *)limbs) + len, 0, count - len);
    } else {
        memcpy(limbs, bytes, count);
    }
#elif BIGNUMBER_LIMB_16BIT
    while (count > 0 && len >= 2) {
        *limbs++ = ((limb_t)(bytes[0])) |
                  (((limb_t)(bytes[1])) << 8);
        bytes += 2;
        --count;
        len -= 2;
    }
    if (count > 0 && len == 1) {
        *limbs++ = ((limb_t)(bytes[0]));
        --count;
    }
    while (count > 0) {
        *limbs++ = 0;
        --count;
    }
#elif BIGNUMBER_LIMB_32BIT
    while (count > 0 && len >= 4) {
        *limbs++ = ((limb_t)(bytes[0])) |
                  (((limb_t)(bytes[1])) <<  8) |
                  (((limb_t)(bytes[2])) << 16) |
                  (((limb_t)(bytes[3])) << 24);
        bytes += 4;
        --count;
        len -= 4;
    }
    if (count > 0 && len > 0) {
        if (len == 3) {
            *limbs++ = ((limb_t)(bytes[0])) |
                      (((limb_t)(bytes[1])) <<  8) |
                      (((limb_t)(bytes[2])) << 16);
        } else if (len == 2) {
            *limbs++ = ((limb_t)(bytes[0])) |
                      (((limb_t)(bytes[1])) <<  8);
        } else {
            *limbs++ = ((limb_t)(bytes[0]));
        }
        --count;
    }
    while (count > 0) {
        *limbs++ = 0;
        --count;
    }
#elif BIGNUMBER_LIMB_64BIT
    while (count > 0 && len >= 8) {
        *limbs++ = ((limb_t)(bytes[0])) |
                  (((limb_t)(bytes[1])) <<  8) |
                  (((limb_t)(bytes[2])) << 16) |
                  (((limb_t)(bytes[3])) << 24) |
                  (((limb_t)(bytes[4])) << 32) |
                  (((limb_t)(bytes[5])) << 40) |
                  (((limb_t)(bytes[6])) << 48) |
                  (((limb_t)(bytes[7])) << 56);
        bytes += 8;
        --count;
        len -= 8;
    }
    if (count > 0 && len > 0) {
        limb_t word = 0;
        uint8_t shift = 0;
        while (len > 0 && shift < 64) {
            word |= (((limb_t)(*bytes++)) << shift);
            shift += 8;
            --len;
        }
        *limbs++ = word;
        --count;
    }
    while (count > 0) {
        *limbs++ = 0;
        --count;
    }
#endif
}
/**
 * \brief Unpacks the big-endian byte representation of a big number
 * into a limb array.
 *
 * \param limbs The limb array, starting with the least significant word.
 * \param count The number of elements in the \a limbs array.
 * \param bytes The bytes to unpack.
 * \param len The number of bytes to unpack.
 *
 * If \a len is shorter than the length of \a limbs, then the high bytes
 * will be filled with zeroes.  If \a len is longer than the length of
 * \a limbs, then the high bytes will be truncated and lost.
 *
 * \sa packBE(), unpackLE()
 */
void BigNumberUtil::unpackBE(limb_t *limbs, size_t count,
                             const uint8_t *bytes, size_t len)
{
#if BIGNUMBER_LIMB_8BIT
    while (count > 0 && len > 0) {
        --count;
        --len;
        *limbs++ = bytes[len];
    }
    memset(limbs, 0, count);
#elif BIGNUMBER_LIMB_16BIT
    bytes += len;
    while (count > 0 && len >= 2) {
        --count;
        bytes -= 2;
        len -= 2;
        *limbs++ = ((limb_t)(bytes[1])) |
                  (((limb_t)(bytes[0])) << 8);
    }
    if (count > 0 && len == 1) {
        --count;
        --bytes;
        *limbs++ = (limb_t)(bytes[0]);
    }
    memset(limbs, 0, count * sizeof(limb_t));
#elif BIGNUMBER_LIMB_32BIT
    bytes += len;
    while (count > 0 && len >= 4) {
        --count;
        bytes -= 4;
        len -= 4;
        *limbs++ = ((limb_t)(bytes[3])) |
                  (((limb_t)(bytes[2])) << 8) |
                  (((limb_t)(bytes[1])) << 16) |
                  (((limb_t)(bytes[0])) << 24);
    }
    if (count > 0) {
        if (len == 3) {
            --count;
            bytes -= 3;
            *limbs++ = ((limb_t)(bytes[2])) |
                      (((limb_t)(bytes[1])) << 8) |
                      (((limb_t)(bytes[0])) << 16);
        } else if (len == 2) {
            --count;
            bytes -= 2;
            *limbs++ = ((limb_t)(bytes[1])) |
                      (((limb_t)(bytes[0])) << 8);
        } else if (len == 1) {
            --count;
            --bytes;
            *limbs++ = (limb_t)(bytes[0]);
        }
    }
    memset(limbs, 0, count * sizeof(limb_t));
#elif BIGNUMBER_LIMB_64BIT
    bytes += len;
    while (count > 0 && len >= 8) {
        --count;
        bytes -= 8;
        len -= 8;
        *limbs++ = ((limb_t)(bytes[7])) |
                  (((limb_t)(bytes[6])) << 8) |
                  (((limb_t)(bytes[5])) << 16) |
                  (((limb_t)(bytes[4])) << 24) |
                  (((limb_t)(bytes[3])) << 32) |
                  (((limb_t)(bytes[2])) << 40) |
                  (((limb_t)(bytes[1])) << 48) |
                  (((limb_t)(bytes[0])) << 56);
    }
    if (count > 0 && len > 0) {
        limb_t word = 0;
        uint8_t shift = 0;
        while (len > 0 && shift < 64) {
            word |= (((limb_t)(*(--bytes))) << shift);
            shift += 8;
            --len;
        }
        *limbs++ = word;
        --count;
    }
    memset(limbs, 0, count * sizeof(limb_t));
#endif
}
/**
 * \brief Packs the little-endian byte representation of a big number
 * into a byte array.
 *
 * \param bytes The byte array to pack into.
 * \param len The number of bytes in the destination \a bytes array.
 * \param limbs The limb array representing the big number, starting with
 * the least significant word.
 * \param count The number of elements in the \a limbs array.
 *
 * If \a len is shorter than the length of \a limbs, then the number will
 * be truncated to the least significant \a len bytes.  If \a len is longer
 * than the length of \a limbs, then the high bytes will be filled with zeroes.
 *
 * \sa unpackLE(), packBE()
 */
void BigNumberUtil::packLE(uint8_t *bytes, size_t len,
                           const limb_t *limbs, size_t count)
{
#if BIGNUMBER_LIMB_8BIT
    if (len <= count) {
        memcpy(bytes, limbs, len);
    } else {
        memcpy(bytes, limbs, count);
        memset(bytes + count, 0, len - count);
    }
#elif CRYPTO_LITTLE_ENDIAN
    count *= sizeof(limb_t);
    if (len <= count) {
        memcpy(bytes, limbs, len);
    } else {
        memcpy(bytes, limbs, count);
        memset(bytes + count, 0, len - count);
    }
#elif BIGNUMBER_LIMB_16BIT
    limb_t word;
    while (count > 0 && len >= 2) {
        word = *limbs++;
        bytes[0] = (uint8_t)word;
        bytes[1] = (uint8_t)(word >> 8);
        --count;
        len -= 2;
        bytes += 2;
    }
    if (count > 0 && len == 1) {
        bytes[0] = (uint8_t)(*limbs);
        --len;
        ++bytes;
    }
    memset(bytes, 0, len);
#elif BIGNUMBER_LIMB_32BIT
    limb_t word;
    while (count > 0 && len >= 4) {
        word = *limbs++;
        bytes[0] = (uint8_t)word;
        bytes[1] = (uint8_t)(word >> 8);
        bytes[2] = (uint8_t)(word >> 16);
        bytes[3] = (uint8_t)(word >> 24);
        --count;
        len -= 4;
        bytes += 4;
    }
    if (count > 0) {
        if (len == 3) {
            word = *limbs;
            bytes[0] = (uint8_t)word;
            bytes[1] = (uint8_t)(word >> 8);
            bytes[2] = (uint8_t)(word >> 16);
            len -= 3;
            bytes += 3;
        } else if (len == 2) {
            word = *limbs;
            bytes[0] = (uint8_t)word;
            bytes[1] = (uint8_t)(word >> 8);
            len -= 2;
            bytes += 2;
        } else if (len == 1) {
            bytes[0] = (uint8_t)(*limbs);
            --len;
            ++bytes;
        }
    }
    memset(bytes, 0, len);
#elif BIGNUMBER_LIMB_64BIT
    limb_t word;
    while (count > 0 && len >= 8) {
        word = *limbs++;
        bytes[0] = (uint8_t)word;
        bytes[1] = (uint8_t)(word >> 8);
        bytes[2] = (uint8_t)(word >> 16);
        bytes[3] = (uint8_t)(word >> 24);
        bytes[4] = (uint8_t)(word >> 32);
        bytes[5] = (uint8_t)(word >> 40);
        bytes[6] = (uint8_t)(word >> 48);
        bytes[7] = (uint8_t)(word >> 56);
        --count;
        len -= 8;
        bytes += 8;
    }
    if (count > 0) {
        word = *limbs;
        while (len > 0) {
            *bytes++ = (uint8_t)word;
            word >>= 8;
            --len;
        }
    }
    memset(bytes, 0, len);
#endif
}
/**
 * \brief Packs the big-endian byte representation of a big number
 * into a byte array.
 *
 * \param bytes The byte array to pack into.
 * \param len The number of bytes in the destination \a bytes array.
 * \param limbs The limb array representing the big number, starting with
 * the least significant word.
 * \param count The number of elements in the \a limbs array.
 *
 * If \a len is shorter than the length of \a limbs, then the number will
 * be truncated to the least significant \a len bytes.  If \a len is longer
 * than the length of \a limbs, then the high bytes will be filled with zeroes.
 *
 * \sa unpackLE(), packBE()
 */
void BigNumberUtil::packBE(uint8_t *bytes, size_t len,
                           const limb_t *limbs, size_t count)
{
#if BIGNUMBER_LIMB_8BIT
    if (len > count) {
        size_t size = len - count;
        memset(bytes, 0, size);
        len -= size;
        bytes += size;
    } else if (len < count) {
        count = len;
    }
    limbs += count;
    while (count > 0) {
        --count;
        *bytes++ = *(--limbs);
    }
#elif BIGNUMBER_LIMB_16BIT
    size_t countBytes = count * sizeof(limb_t);
    limb_t word;
    if (len >= countBytes) {
        size_t size = len - countBytes;
        memset(bytes, 0, size);
        len -= size;
        bytes += size;
        limbs += count;
    } else {
        count = len / sizeof(limb_t);
        limbs += count;
        if ((len & 1) != 0)
            *bytes++ = (uint8_t)(*limbs);
    }
    while (count > 0) {
        --count;
        word = *(--limbs);
        *bytes++ = (uint8_t)(word >> 8);
        *bytes++ = (uint8_t)word;
    }
#elif BIGNUMBER_LIMB_32BIT
    size_t countBytes = count * sizeof(limb_t);
    limb_t word;
    if (len >= countBytes) {
        size_t size = len - countBytes;
        memset(bytes, 0, size);
        len -= size;
        bytes += size;
        limbs += count;
    } else {
        count = len / sizeof(limb_t);
        limbs += count;
        if ((len & 3) == 3) {
            word = *limbs;
            *bytes++ = (uint8_t)(word >> 16);
            *bytes++ = (uint8_t)(word >> 8);
            *bytes++ = (uint8_t)word;
        } else if ((len & 3) == 2) {
            word = *limbs;
            *bytes++ = (uint8_t)(word >> 8);
            *bytes++ = (uint8_t)word;
        } else if ((len & 3) == 1) {
            *bytes++ = (uint8_t)(*limbs);
        }
    }
    while (count > 0) {
        --count;
        word = *(--limbs);
        *bytes++ = (uint8_t)(word >> 24);
        *bytes++ = (uint8_t)(word >> 16);
        *bytes++ = (uint8_t)(word >> 8);
        *bytes++ = (uint8_t)word;
    }
#elif BIGNUMBER_LIMB_64BIT
    size_t countBytes = count * sizeof(limb_t);
    limb_t word;
    if (len >= countBytes) {
        size_t size = len - countBytes;
        memset(bytes, 0, size);
        len -= size;
        bytes += size;
        limbs += count;
    } else {
        count = len / sizeof(limb_t);
        limbs += count;
        uint8_t size = len & 7;
        uint8_t shift = size * 8;
        word = *limbs;
        while (size > 0) {
            shift -= 8;
            *bytes++ = (uint8_t)(word >> shift);
            --size;
        }
    }
    while (count > 0) {
        --count;
        word = *(--limbs);
        *bytes++ = (uint8_t)(word >> 56);
        *bytes++ = (uint8_t)(word >> 48);
        *bytes++ = (uint8_t)(word >> 40);
        *bytes++ = (uint8_t)(word >> 32);
        *bytes++ = (uint8_t)(word >> 24);
        *bytes++ = (uint8_t)(word >> 16);
        *bytes++ = (uint8_t)(word >> 8);
        *bytes++ = (uint8_t)word;
    }
#endif
}
/**
 * \brief Adds two big numbers.
 *
 * \param result The result of the addition.  This can be the same
 * as either \a x or \a y.
 * \param x The first big number.
 * \param y The second big number.
 * \param size The size of the values in limbs.
 *
 * \return Returns 1 if there was a carry out or 0 if there was no carry out.
 *
 * \sa sub(), mul()
 */
limb_t BigNumberUtil::add(limb_t *result, const limb_t *x,
                          const limb_t *y, size_t size)
{
    dlimb_t carry = 0;
    while (size > 0) {
        carry += *x++;
        carry += *y++;
        *result++ = (limb_t)carry;
        carry >>= LIMB_BITS;
        --size;
    }
    return (limb_t)carry;
}
/**
 * \brief Subtracts one big number from another.
 *
 * \param result The result of the subtraction.  This can be the same
 * as either \a x or \a y.
 * \param x The first big number.
 * \param y The second big number to subtract from \a x.
 * \param size The size of the values in limbs.
 *
 * \return Returns 1 if there was a borrow, or 0 if there was no borrow.
 *
 * \sa add(), mul()
 */
limb_t BigNumberUtil::sub(limb_t *result, const limb_t *x,
                          const limb_t *y, size_t size)
{
    dlimb_t borrow = 0;
    while (size > 0) {
        borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
        *result++ = (limb_t)borrow;
        --size;
    }
    return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
}
/**
 * \brief Multiplies two big numbers.
 *
 * \param result The result of the multiplication.  The array must be
 * \a xcount + \a ycount limbs in size.
 * \param x Points to the first value to multiply.
 * \param xcount The number of limbs in \a x.
 * \param y Points to the second value to multiply.
 * \param ycount The number of limbs in \a y.
 *
 * \sa mul_P()
 */
void BigNumberUtil::mul(limb_t *result, const limb_t *x, size_t xcount,
                        const limb_t *y, size_t ycount)
{
    size_t i, j;
    dlimb_t carry;
    limb_t word;
    const limb_t *xx;
    limb_t *rr;
    // Multiply the lowest limb of y by x.
    carry = 0;
    word = y[0];
    xx = x;
    rr = result;
    for (i = 0; i < xcount; ++i) {
        carry += ((dlimb_t)(*xx++)) * word;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    *rr = (limb_t)carry;
    // Multiply and add the remaining limbs of y by x.
    for (i = 1; i < ycount; ++i) {
        word = y[i];
        carry = 0;
        xx = x;
        rr = result + i;
        for (j = 0; j < xcount; ++j) {
            carry += ((dlimb_t)(*xx++)) * word;
            carry += *rr;
            *rr++ = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        *rr = (limb_t)carry;
    }
}
/**
 * \brief Reduces \a x modulo \a y using subtraction.
 *
 * \param result The result of the reduction.  This can be the
 * same as \a x.
 * \param x The number to be reduced.
 * \param y The base to use for the modulo reduction.
 * \param size The size of the values in limbs.
 *
 * It is assumed that \a x is less than \a y * 2 so that a single
 * conditional subtraction will bring it down below \a y.  The reduction
 * is performed in constant time.
 *
 * \sa reduceQuick_P()
 */
void BigNumberUtil::reduceQuick(limb_t *result, const limb_t *x,
                                const limb_t *y, size_t size)
{
    // Subtract "y" from "x" and turn the borrow into an AND mask.
    limb_t mask = sub(result, x, y, size);
    mask = (~mask) + 1;
    // Add "y" back to the result if the mask is non-zero.
    dlimb_t carry = 0;
    while (size > 0) {
        carry += *result;
        carry += (*y++ & mask);
        *result++ = (limb_t)carry;
        carry >>= LIMB_BITS;
        --size;
    }
}
/**
 * \brief Adds two big numbers where one of them is in program memory.
 *
 * \param result The result of the addition.  This can be the same as \a x.
 * \param x The first big number.
 * \param y The second big number.  This must point into program memory.
 * \param size The size of the values in limbs.
 *
 * \return Returns 1 if there was a carry out or 0 if there was no carry out.
 *
 * \sa sub_P(), mul_P()
 */
limb_t BigNumberUtil::add_P(limb_t *result, const limb_t *x,
                            const limb_t *y, size_t size)
{
    dlimb_t carry = 0;
    while (size > 0) {
        carry += *x++;
        carry += pgm_read_limb(y++);
        *result++ = (limb_t)carry;
        carry >>= LIMB_BITS;
        --size;
    }
    return (limb_t)carry;
}
/**
 * \brief Subtracts one big number from another where one is in program memory.
 *
 * \param result The result of the subtraction.  This can be the same as \a x.
 * \param x The first big number.
 * \param y The second big number to subtract from \a x.  This must point
 * into program memory.
 * \param size The size of the values in limbs.
 *
 * \return Returns 1 if there was a borrow, or 0 if there was no borrow.
 *
 * \sa add_P(), mul_P()
 */
limb_t BigNumberUtil::sub_P(limb_t *result, const limb_t *x,
                            const limb_t *y, size_t size)
{
    dlimb_t borrow = 0;
    while (size > 0) {
        borrow = ((dlimb_t)(*x++)) - pgm_read_limb(y++) - ((borrow >> LIMB_BITS) & 0x01);
        *result++ = (limb_t)borrow;
        --size;
    }
    return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
}
/**
 * \brief Multiplies two big numbers where one is in program memory.
 *
 * \param result The result of the multiplication.  The array must be
 * \a xcount + \a ycount limbs in size.
 * \param x Points to the first value to multiply.
 * \param xcount The number of limbs in \a x.
 * \param y Points to the second value to multiply.  This must point
 * into program memory.
 * \param ycount The number of limbs in \a y.
 *
 * \sa mul()
 */
void BigNumberUtil::mul_P(limb_t *result, const limb_t *x, size_t xcount,
                          const limb_t *y, size_t ycount)
{
    size_t i, j;
    dlimb_t carry;
    limb_t word;
    const limb_t *xx;
    limb_t *rr;
    // Multiply the lowest limb of y by x.
    carry = 0;
    word = pgm_read_limb(&(y[0]));
    xx = x;
    rr = result;
    for (i = 0; i < xcount; ++i) {
        carry += ((dlimb_t)(*xx++)) * word;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    *rr = (limb_t)carry;
    // Multiply and add the remaining limb of y by x.
    for (i = 1; i < ycount; ++i) {
        word = pgm_read_limb(&(y[i]));
        carry = 0;
        xx = x;
        rr = result + i;
        for (j = 0; j < xcount; ++j) {
            carry += ((dlimb_t)(*xx++)) * word;
            carry += *rr;
            *rr++ = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        *rr = (limb_t)carry;
    }
}
/**
 * \brief Reduces \a x modulo \a y using subtraction where \a y is
 * in program memory.
 *
 * \param result The result of the reduction.  This can be the
 * same as \a x.
 * \param x The number to be reduced.
 * \param y The base to use for the modulo reduction.  This must point
 * into program memory.
 * \param size The size of the values in limbs.
 *
 * It is assumed that \a x is less than \a y * 2 so that a single
 * conditional subtraction will bring it down below \a y.  The reduction
 * is performed in constant time.
 *
 * \sa reduceQuick()
 */
void BigNumberUtil::reduceQuick_P(limb_t *result, const limb_t *x,
                                  const limb_t *y, size_t size)
{
    // Subtract "y" from "x" and turn the borrow into an AND mask.
    limb_t mask = sub_P(result, x, y, size);
    mask = (~mask) + 1;
    // Add "y" back to the result if the mask is non-zero.
    dlimb_t carry = 0;
    while (size > 0) {
        carry += *result;
        carry += (pgm_read_limb(y++) & mask);
        *result++ = (limb_t)carry;
        carry >>= LIMB_BITS;
        --size;
    }
}
/**
 * \brief Determine if a big number is zero.
 *
 * \param x Points to the number to test.
 * \param size The number of limbs in \a x.
 * \return Returns 1 if \a x is zero or 0 otherwise.
 *
 * This function attempts to make the determination in constant time.
 */
limb_t BigNumberUtil::isZero(const limb_t *x, size_t size)
{
    limb_t word = 0;
    while (size > 0) {
        word |= *x++;
        --size;
    }
    return (limb_t)(((((dlimb_t)1) << LIMB_BITS) - word) >> LIMB_BITS);
}
src/modules/Crypto/BigNumberUtil.h
New file
@@ -0,0 +1,110 @@
/*
 * 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.
 */
#ifndef CRYPTO_BIGNUMBERUTIL_h
#define CRYPTO_BIGNUMBERUTIL_h
#include <inttypes.h>
#include <stddef.h>
// Define exactly one of these to 1 to set the size of the basic limb type.
#if defined(__AVR__) || defined(ESP8266)
// 16-bit limbs seem to give the best performance on 8-bit AVR micros.
// They also seem to give better performance on ESP8266 as well.
#define BIGNUMBER_LIMB_8BIT  0
#define BIGNUMBER_LIMB_16BIT 1
#define BIGNUMBER_LIMB_32BIT 0
#define BIGNUMBER_LIMB_64BIT 0
#elif defined(__GNUC__) && __WORDSIZE == 64
// 64-bit system with 128-bit double limbs.
#define BIGNUMBER_LIMB_8BIT  0
#define BIGNUMBER_LIMB_16BIT 0
#define BIGNUMBER_LIMB_32BIT 0
#define BIGNUMBER_LIMB_64BIT 1
#else
// On all other platforms, assume 32-bit is best.
#define BIGNUMBER_LIMB_8BIT  0
#define BIGNUMBER_LIMB_16BIT 0
#define BIGNUMBER_LIMB_32BIT 1
#define BIGNUMBER_LIMB_64BIT 0
#endif
// Define the limb types to use on this platform.
#if BIGNUMBER_LIMB_8BIT
typedef uint8_t limb_t;
typedef int8_t slimb_t;
typedef uint16_t dlimb_t;
#elif BIGNUMBER_LIMB_16BIT
typedef uint16_t limb_t;
typedef int16_t slimb_t;
typedef uint32_t dlimb_t;
#elif BIGNUMBER_LIMB_32BIT
typedef uint32_t limb_t;
typedef int32_t slimb_t;
typedef uint64_t dlimb_t;
#elif BIGNUMBER_LIMB_64BIT
typedef uint64_t limb_t;
typedef int64_t slimb_t;
typedef unsigned __int128 dlimb_t;
#else
#error "limb_t must be 8, 16, 32, or 64 bits in size"
#endif
class BigNumberUtil
{
public:
    static void unpackLE(limb_t *limbs, size_t count,
                         const uint8_t *bytes, size_t len);
    static void unpackBE(limb_t *limbs, size_t count,
                         const uint8_t *bytes, size_t len);
    static void packLE(uint8_t *bytes, size_t len,
                       const limb_t *limbs, size_t count);
    static void packBE(uint8_t *bytes, size_t len,
                       const limb_t *limbs, size_t count);
    static limb_t add(limb_t *result, const limb_t *x,
                      const limb_t *y, size_t size);
    static limb_t sub(limb_t *result, const limb_t *x,
                      const limb_t *y, size_t size);
    static void mul(limb_t *result, const limb_t *x, size_t xcount,
                    const limb_t *y, size_t ycount);
    static void reduceQuick(limb_t *result, const limb_t *x,
                            const limb_t *y, size_t size);
    static limb_t add_P(limb_t *result, const limb_t *x,
                        const limb_t *y, size_t size);
    static limb_t sub_P(limb_t *result, const limb_t *x,
                        const limb_t *y, size_t size);
    static void mul_P(limb_t *result, const limb_t *x, size_t xcount,
                      const limb_t *y, size_t ycount);
    static void reduceQuick_P(limb_t *result, const limb_t *x,
                              const limb_t *y, size_t size);
    static limb_t isZero(const limb_t *x, size_t size);
private:
    // Constructor and destructor are private - cannot instantiate this class.
    BigNumberUtil() {}
    ~BigNumberUtil() {}
};
#endif
src/modules/Crypto/BlockCipher.cpp
New file
@@ -0,0 +1,124 @@
/*
 * 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 "BlockCipher.h"
/**
 * \class BlockCipher BlockCipher.h <BlockCipher.h>
 * \brief Abstract base class for block ciphers.
 *
 * Block ciphers always operate in electronic codebook (ECB) mode.
 * Higher-level classes such as CFB128 and CTR128 wrap the block cipher to
 * create more useful classes for encryption and decryption of bulk data.
 *
 * References: http://en.wikipedia.org/wiki/Block_cipher,
 * http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
 */
/**
 * \brief Constructs a block cipher.
 */
BlockCipher::BlockCipher()
{
}
/**
 * \brief Destroys this block cipher object.
 *
 * Subclasses are responsible for clearing temporary key schedules
 * and other buffers so as to avoid leaking sensitive information.
 *
 * \sa clear()
 */
BlockCipher::~BlockCipher()
{
}
/**
 * \fn size_t BlockCipher::blockSize() const
 * \brief Size of a single block processed by this cipher, in bytes.
 *
 * \return Returns the size of a block in bytes.
 *
 * \sa keySize(), encryptBlock()
 */
/**
 * \fn size_t BlockCipher::keySize() const
 * \brief Default size of the key for this block cipher, in bytes.
 *
 * This value indicates the default, or recommended, size for the key.
 *
 * \sa setKey(), blockSize()
 */
/**
 * \fn bool BlockCipher::setKey(const uint8_t *key, size_t len)
 * \brief Sets the key to use for future encryption and decryption operations.
 *
 * \param key The key to use.
 * \param len The length of the key.
 * \return Returns false if the key length is not supported, or the key
 * is somehow "weak" and unusable by this cipher.
 *
 * Use clear() or the destructor to remove the key and any other sensitive
 * data from the object once encryption or decryption is complete.
 *
 * \sa keySize(), clear()
 */
/**
 * \fn void BlockCipher::encryptBlock(uint8_t *output, const uint8_t *input)
 * \brief Encrypts a single block using this cipher.
 *
 * \param output The output buffer to put the ciphertext into.
 * Must be at least blockSize() bytes in length.
 * \param input The input buffer to read the plaintext from which is
 * allowed to overlap with \a output.  Must be at least blockSize()
 * bytes in length.
 *
 * \sa decryptBlock(), blockSize()
 */
/**
 * \fn void BlockCipher::decryptBlock(uint8_t *output, const uint8_t *input)
 * \brief Decrypts a single block using this cipher.
 *
 * \param output The output buffer to put the plaintext into.
 * Must be at least blockSize() bytes in length.
 * \param input The input buffer to read the ciphertext from which is
 * allowed to overlap with \a output.  Must be at least blockSize()
 * bytes in length.
 *
 * \sa encryptBlock(), blockSize()
 */
/**
 * \fn void BlockCipher::clear()
 * \brief Clears all security-sensitive state from this block cipher.
 *
 * Security-sensitive information includes key schedules and any
 * temporary state that is used by encryptBlock() or decryptBlock()
 * which is stored in the object itself.
 *
 * \sa setKey(), encryptBlock(), decryptBlock()
 */
src/modules/Crypto/BlockCipher.h
New file
@@ -0,0 +1,46 @@
/*
 * 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.
 */
#ifndef CRYPTO_BLOCKCIPHER_h
#define CRYPTO_BLOCKCIPHER_h
#include <inttypes.h>
#include <stddef.h>
class BlockCipher
{
public:
    BlockCipher();
    virtual ~BlockCipher();
    virtual size_t blockSize() const = 0;
    virtual size_t keySize() const = 0;
    virtual bool setKey(const uint8_t *key, size_t len) = 0;
    virtual void encryptBlock(uint8_t *output, const uint8_t *input) = 0;
    virtual void decryptBlock(uint8_t *output, const uint8_t *input) = 0;
    virtual void clear() = 0;
};
#endif
src/modules/Crypto/CTR.cpp
New file
@@ -0,0 +1,220 @@
/*
 * 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 "CTR.h"
#include "Crypto.h"
#include <string.h>
/**
 * \class CTRCommon CTR.h <CTR.h>
 * \brief Concrete base class to assist with implementing CTR mode for
 * 128-bit block ciphers.
 *
 * Reference: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
 *
 * \sa CTR
 */
/**
 * \brief Constructs a new cipher in CTR mode.
 *
 * This constructor should be followed by a call to setBlockCipher().
 */
CTRCommon::CTRCommon()
    : blockCipher(0)
    , posn(16)
    , counterStart(0)
{
}
CTRCommon::~CTRCommon()
{
    // It is assumed that the subclass will clear sensitive
    // information in the block cipher.
    clean(counter);
    clean(state);
}
size_t CTRCommon::keySize() const
{
    return blockCipher->keySize();
}
size_t CTRCommon::ivSize() const
{
    return 16;
}
/**
 * \brief Sets the counter size for the IV.
 *
 * \param size The number of bytes on the end of the counter block
 * that are relevant when incrementing, between 1 and 16.
 * \return Returns false if the \a size value is not between 1 and 16.
 *
 * When the counter is incremented during encrypt(), only the last
 * \a size bytes are considered relevant.  This can be useful
 * to improve performance when the higher level protocol specifies that
 * only the least significant N bytes "count".  The high level protocol
 * should explicitly generate a new initial counter value and key long
 * before the \a size bytes overflow and wrap around.
 *
 * By default, the counter size is 16 which is the same as the block size
 * of the underlying block cipher.
 *
 * \sa setIV()
 */
bool CTRCommon::setCounterSize(size_t size)
{
    if (size < 1 || size > 16)
        return false;
    counterStart = 16 - size;
    return true;
}
bool CTRCommon::setKey(const uint8_t *key, size_t len)
{
    // Verify the cipher's block size, just in case.
    if (blockCipher->blockSize() != 16)
        return false;
    // Set the key on the underlying block cipher.
    return blockCipher->setKey(key, len);
}
/**
 * \brief Sets the initial counter value to use for future encryption and
 * decryption operations.
 *
 * \param iv The initial counter value which must contain exactly 16 bytes.
 * \param len The length of the counter value, which mut be 16.
 * \return Returns false if \a len is not exactly 16.
 *
 * The precise method to generate the initial counter is not defined by
 * this class.  Usually higher level protocols like SSL/TLS and SSH
 * specify how to construct the initial counter value.  This class merely
 * increments the counter every time a new block of keystream data is needed.
 *
 * \sa encrypt(), setCounterSize()
 */
bool CTRCommon::setIV(const uint8_t *iv, size_t len)
{
    if (len != 16)
        return false;
    memcpy(counter, iv, len);
    posn = 16;
    return true;
}
void CTRCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    while (len > 0) {
        if (posn >= 16) {
            // Generate a new encrypted counter block.
            blockCipher->encryptBlock(state, counter);
            posn = 0;
            // Increment the counter, taking care not to reveal
            // any timing information about the starting value.
            // We iterate through the entire counter region even
            // if we could stop earlier because a byte is non-zero.
            uint16_t temp = 1;
            uint8_t index = 16;
            while (index > counterStart) {
                --index;
                temp += counter[index];
                counter[index] = (uint8_t)temp;
                temp >>= 8;
            }
        }
        uint8_t templen = 16 - posn;
        if (templen > len)
            templen = len;
        len -= templen;
        while (templen > 0) {
            *output++ = *input++ ^ state[posn++];
            --templen;
        }
    }
}
void CTRCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    encrypt(output, input, len);
}
void CTRCommon::clear()
{
    blockCipher->clear();
    clean(counter);
    clean(state);
    posn = 16;
}
/**
 * \fn void CTRCommon::setBlockCipher(BlockCipher *cipher)
 * \brief Sets the block cipher to use for this CTR object.
 *
 * \param cipher The block cipher to use to implement CTR mode,
 * which must have a block size of 16 bytes (128 bits).
 *
 * \note This class only works with block ciphers whose block size is
 * 16 bytes (128 bits).  If the \a cipher has a different block size,
 * then setKey() will fail and return false.
 */
/**
 * \class CTR CTR.h <CTR.h>
 * \brief Implementation of the Counter (CTR) mode for 128-bit block ciphers.
 *
 * Counter mode converts a block cipher into a stream cipher.  The specific
 * block cipher is passed as the template parameter T and the key is
 * specified via the setKey() function.
 *
 * Keystream blocks are generated by encrypting an increasing counter value
 * and XOR'ing it with each byte of input.  The encrypt() and decrypt()
 * operations are identical.
 *
 * The template parameter T must be a concrete subclass of BlockCipher
 * indicating the specific block cipher to use.  For example, the following
 * creates a CTR object using AES256 as the underlying cipher:
 *
 * \code
 * CTR<AES256> ctr;
 * ctr.setKey(key, 32);
 * ctr.setIV(iv, 16);
 * ctr.setCounterSize(4);
 * ctr.encrypt(output, input, len);
 * \endcode
 *
 * In this example, the last 4 bytes of the IV are incremented to count
 * blocks.  The remaining bytes are left unchanged from block to block.
 *
 * Reference: http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
 *
 * \sa CFB, OFB, CBC
 */
/**
 * \fn CTR::CTR()
 * \brief Constructs a new CTR object for the 128-bit block cipher T.
 */
src/modules/Crypto/CTR.h
New file
@@ -0,0 +1,69 @@
/*
 * 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.
 */
#ifndef CRYPTO_CTR_h
#define CRYPTO_CTR_h
#include "Cipher.h"
#include "BlockCipher.h"
class CTRCommon : public Cipher
{
public:
    virtual ~CTRCommon();
    size_t keySize() const;
    size_t ivSize() const;
    bool setCounterSize(size_t size);
    bool setKey(const uint8_t *key, size_t len);
    bool setIV(const uint8_t *iv, size_t len);
    void encrypt(uint8_t *output, const uint8_t *input, size_t len);
    void decrypt(uint8_t *output, const uint8_t *input, size_t len);
    void clear();
protected:
    CTRCommon();
    void setBlockCipher(BlockCipher *cipher) { blockCipher = cipher; }
private:
    BlockCipher *blockCipher;
    uint8_t counter[16];
    uint8_t state[16];
    uint8_t posn;
    uint8_t counterStart;
};
template <typename T>
class CTR : public CTRCommon
{
public:
    CTR() { setBlockCipher(&cipher); }
private:
    T cipher;
};
#endif
src/modules/Crypto/ChaCha.cpp
New file
@@ -0,0 +1,281 @@
/*
 * 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 "ChaCha.h"
#include "Crypto.h"
#include "utility/RotateUtil.h"
#include "utility/EndianUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
 * \class ChaCha ChaCha.h <ChaCha.h>
 * \brief ChaCha stream cipher.
 *
 * ChaCha is a stream cipher that takes a key, an 8-byte nonce/IV, and a
 * counter and hashes them to generate a keystream to XOR with the plaintext.
 * Variations on the ChaCha cipher use 8, 12, or 20 rounds of hashing
 * operations with either 128-bit or 256-bit keys.
 *
 * Reference: http://cr.yp.to/chacha.html
 */
/**
 * \brief Constructs a new ChaCha stream cipher.
 *
 * \param numRounds Number of encryption rounds to use; usually 8, 12, or 20.
 */
ChaCha::ChaCha(uint8_t numRounds)
    : rounds(numRounds)
    , posn(64)
{
}
ChaCha::~ChaCha()
{
    clean(block);
    clean(stream);
}
size_t ChaCha::keySize() const
{
    // Default key size is 256-bit, but any key size is allowed.
    return 32;
}
size_t ChaCha::ivSize() const
{
    // We return 8 but we also support 12-byte nonces in setIV().
    return 8;
}
/**
 * \fn uint8_t ChaCha::numRounds() const
 * \brief Returns the number of encryption rounds; usually 8, 12, or 20.
 *
 * \sa setNumRounds()
 */
/**
 * \fn void ChaCha::setNumRounds(uint8_t numRounds)
 * \brief Sets the number of encryption rounds.
 *
 * \param numRounds The number of encryption rounds; usually 8, 12, or 20.
 *
 * \sa numRounds()
 */
bool ChaCha::setKey(const uint8_t *key, size_t len)
{
    static const char tag128[] PROGMEM = "expand 16-byte k";
    static const char tag256[] PROGMEM = "expand 32-byte k";
    if (len <= 16) {
        memcpy_P(block, tag128, 16);
        memcpy(block + 16, key, len);
        memcpy(block + 32, key, len);
        if (len < 16) {
            memset(block + 16 + len, 0, 16 - len);
            memset(block + 32 + len, 0, 16 - len);
        }
    } else {
        if (len > 32)
            len = 32;
        memcpy_P(block, tag256, 16);
        memcpy(block + 16, key, len);
        if (len < 32)
            memset(block + 16 + len, 0, 32 - len);
    }
    posn = 64;
    return true;
}
bool ChaCha::setIV(const uint8_t *iv, size_t len)
{
    // From draft-nir-cfrg-chacha20-poly1305-10.txt, we can use either
    // 64-bit or 96-bit nonces.  The 96-bit nonce consists of the high
    // word of the counter prepended to a regular 64-bit nonce for ChaCha.
    if (len == 8) {
        memset(block + 48, 0, 8);
        memcpy(block + 56, iv, len);
        posn = 64;
        return true;
    } else if (len == 12) {
        memset(block + 48, 0, 4);
        memcpy(block + 52, iv, len);
        posn = 64;
        return true;
    } else {
        return false;
    }
}
/**
 * \brief Sets the starting counter for encryption.
 *
 * \param counter A 4-byte or 8-byte value to use for the starting counter
 * instead of the default value of zero.
 * \param len The length of the counter, which must be 4 or 8.
 * \return Returns false if \a len is not 4 or 8.
 *
 * This function must be called after setIV() and before the first call
 * to encrypt().  It is used to specify a different starting value than
 * zero for the counter portion of the hash input.
 *
 * \sa setIV()
 */
bool ChaCha::setCounter(const uint8_t *counter, size_t len)
{
    // Normally both the IV and the counter are 8 bytes in length.
    // However, if the IV was 12 bytes, then a 4 byte counter can be used.
    if (len == 4 || len == 8) {
        memcpy(block + 48, counter, len);
        posn = 64;
        return true;
    } else {
        return false;
    }
}
void ChaCha::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    while (len > 0) {
        if (posn >= 64) {
            // Generate a new encrypted counter block.
            hashCore((uint32_t *)stream, (const uint32_t *)block, rounds);
            posn = 0;
            // Increment the counter, taking care not to reveal
            // any timing information about the starting value.
            // We iterate through the entire counter region even
            // if we could stop earlier because a byte is non-zero.
            uint16_t temp = 1;
            uint8_t index = 48;
            while (index < 56) {
                temp += block[index];
                block[index] = (uint8_t)temp;
                temp >>= 8;
                ++index;
            }
        }
        uint8_t templen = 64 - posn;
        if (templen > len)
            templen = len;
        len -= templen;
        while (templen > 0) {
            *output++ = *input++ ^ stream[posn++];
            --templen;
        }
    }
}
void ChaCha::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    encrypt(output, input, len);
}
/**
 * \brief Generates a single block of output direct from the keystream.
 *
 * \param output The output buffer to fill with keystream bytes.
 *
 * Unlike encrypt(), this function does not XOR the keystream with
 * plaintext data.  Instead it generates the keystream directly into
 * the caller-supplied buffer.  This is useful if the caller knows
 * that the plaintext is all-zeroes.
 *
 * \sa encrypt()
 */
void ChaCha::keystreamBlock(uint32_t *output)
{
    // Generate the hash output directly into the caller-supplied buffer.
    hashCore(output, (const uint32_t *)block, rounds);
    posn = 64;
    // Increment the lowest counter byte.  We are assuming that the caller
    // is ChaChaPoly::setKey() and that the previous counter value was zero.
    block[48] = 1;
}
void ChaCha::clear()
{
    clean(block);
    clean(stream);
    posn = 64;
}
// Perform a ChaCha quarter round operation.
#define quarterRound(a, b, c, d)    \
    do { \
        uint32_t _b = (b); \
        uint32_t _a = (a) + _b; \
        uint32_t _d = leftRotate((d) ^ _a, 16); \
        uint32_t _c = (c) + _d; \
        _b = leftRotate12(_b ^ _c); \
        _a += _b; \
        (d) = _d = leftRotate(_d ^ _a, 8); \
        _c += _d; \
        (a) = _a; \
        (b) = leftRotate7(_b ^ _c); \
        (c) = _c; \
    } while (0)
/**
 * \brief Executes the ChaCha hash core on an input memory block.
 *
 * \param output Output memory block, must be at least 16 words in length
 * and must not overlap with \a input.
 * \param input Input memory block, must be at least 16 words in length.
 * \param rounds Number of ChaCha rounds to perform; usually 8, 12, or 20.
 *
 * This function is provided for the convenience of applications that need
 * access to the ChaCha hash core without the higher-level processing that
 * turns the core into a stream cipher.
 */
void ChaCha::hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds)
{
    uint8_t posn;
    // Copy the input buffer to the output prior to the first round
    // and convert from little-endian to host byte order.
    for (posn = 0; posn < 16; ++posn)
        output[posn] = le32toh(input[posn]);
    // Perform the ChaCha rounds in sets of two.
    for (; rounds >= 2; rounds -= 2) {
        // Column round.
        quarterRound(output[0], output[4], output[8],  output[12]);
        quarterRound(output[1], output[5], output[9],  output[13]);
        quarterRound(output[2], output[6], output[10], output[14]);
        quarterRound(output[3], output[7], output[11], output[15]);
        // Diagonal round.
        quarterRound(output[0], output[5], output[10], output[15]);
        quarterRound(output[1], output[6], output[11], output[12]);
        quarterRound(output[2], output[7], output[8],  output[13]);
        quarterRound(output[3], output[4], output[9],  output[14]);
    }
    // Add the original input to the final output, convert back to
    // little-endian, and return the result.
    for (posn = 0; posn < 16; ++posn)
        output[posn] = htole32(output[posn] + le32toh(input[posn]));
}
src/modules/Crypto/ChaCha.h
New file
@@ -0,0 +1,64 @@
/*
 * 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.
 */
#ifndef CRYPTO_CHACHA_h
#define CRYPTO_CHACHA_h
#include "Cipher.h"
class ChaChaPoly;
class ChaCha : public Cipher
{
public:
    explicit ChaCha(uint8_t numRounds = 20);
    virtual ~ChaCha();
    size_t keySize() const;
    size_t ivSize() const;
    uint8_t numRounds() const { return rounds; }
    void setNumRounds(uint8_t numRounds) { rounds = numRounds; }
    bool setKey(const uint8_t *key, size_t len);
    bool setIV(const uint8_t *iv, size_t len);
    bool setCounter(const uint8_t *counter, size_t len);
    void encrypt(uint8_t *output, const uint8_t *input, size_t len);
    void decrypt(uint8_t *output, const uint8_t *input, size_t len);
    void clear();
    static void hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds);
private:
    uint8_t block[64];
    uint8_t stream[64];
    uint8_t rounds;
    uint8_t posn;
    void keystreamBlock(uint32_t *output);
    friend class ChaChaPoly;
};
#endif
src/modules/Crypto/ChaChaPoly.cpp
New file
@@ -0,0 +1,170 @@
/*
 * 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 "ChaChaPoly.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include <string.h>
/**
 * \class ChaChaPoly ChaChaPoly.h <ChaChaPoly.h>
 * \brief Authenticated cipher based on ChaCha and Poly1305
 *
 * ChaChaPoly is an authenticated cipher based on a combination of
 * ChaCha with 20 rounds for encryption and Poly1305 for authentication.
 * The resulting cipher has a 256-bit key, a 64-bit or 96-bit
 * initialization vector, and a 128-bit authentication tag.
 *
 * Reference: https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-10
 *
 * \sa ChaCha, Poly1305, AuthenticatedCipher
 */
/**
 * \brief Constructs a new ChaChaPoly authenticated cipher.
 */
ChaChaPoly::ChaChaPoly()
{
    state.authSize = 0;
    state.dataSize = 0;
    state.dataStarted = false;
    state.ivSize = 8;
}
/**
 * \brief Destroys this ChaChaPoly authenticated cipher.
 */
ChaChaPoly::~ChaChaPoly()
{
    clean(state);
}
size_t ChaChaPoly::keySize() const
{
    // Default key size is 256-bit, but any key size is allowed.
    return 32;
}
size_t ChaChaPoly::ivSize() const
{
    // Return 8 but we also support 12-byte nonces in setIV().
    return 8;
}
size_t ChaChaPoly::tagSize() const
{
    // Any tag size between 1 and 16 is supported.
    return 16;
}
bool ChaChaPoly::setKey(const uint8_t *key, size_t len)
{
    return chacha.setKey(key, len);
}
bool ChaChaPoly::setIV(const uint8_t *iv, size_t len)
{
    // ChaCha::setIV() supports both 64-bit and 96-bit nonces.
    if (!chacha.setIV(iv, len))
        return false;
    // Generate the key and nonce to use for Poly1305.
    uint32_t data[16];
    chacha.keystreamBlock(data);
    poly1305.reset(data);
    memcpy(state.nonce, data + 4, 16);
    clean(data);
    // Reset the size counters for the auth data and payload.
    state.authSize = 0;
    state.dataSize = 0;
    state.dataStarted = false;
    state.ivSize = len;
    return true;
}
void ChaChaPoly::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    if (!state.dataStarted) {
        poly1305.pad();
        state.dataStarted = true;
    }
    chacha.encrypt(output, input, len);
    poly1305.update(output, len);
    state.dataSize += len;
}
void ChaChaPoly::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    if (!state.dataStarted) {
        poly1305.pad();
        state.dataStarted = true;
    }
    poly1305.update(input, len);
    chacha.encrypt(output, input, len); // encrypt() is the same as decrypt()
    state.dataSize += len;
}
void ChaChaPoly::addAuthData(const void *data, size_t len)
{
    if (!state.dataStarted) {
        poly1305.update(data, len);
        state.authSize += len;
    }
}
void ChaChaPoly::computeTag(void *tag, size_t len)
{
    uint64_t sizes[2];
    // Pad the final Poly1305 block and then hash the sizes.
    poly1305.pad();
    sizes[0] = htole64(state.authSize);
    sizes[1] = htole64(state.dataSize);
    poly1305.update(sizes, sizeof(sizes));
    // Compute the tag and copy it to the return buffer.
    poly1305.finalize(state.nonce, tag, len);
    clean(sizes);
}
bool ChaChaPoly::checkTag(const void *tag, size_t len)
{
    // Can never match if the expected tag length is too long.
    if (len > 16)
        return false;
    // Compute the tag and check it.
    uint8_t temp[16];
    computeTag(temp, len);
    bool equal = secure_compare(temp, tag, len);
    clean(temp);
    return equal;
}
void ChaChaPoly::clear()
{
    chacha.clear();
    poly1305.clear();
    clean(state);
    state.ivSize = 8;
}
src/modules/Crypto/ChaChaPoly.h
New file
@@ -0,0 +1,65 @@
/*
 * 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.
 */
#ifndef CRYPTO_CHACHAPOLY_H
#define CRYPTO_CHACHAPOLY_H
#include "AuthenticatedCipher.h"
#include "ChaCha.h"
#include "Poly1305.h"
class ChaChaPoly : public AuthenticatedCipher
{
public:
    ChaChaPoly();
    virtual ~ChaChaPoly();
    size_t keySize() const;
    size_t ivSize() const;
    size_t tagSize() const;
    bool setKey(const uint8_t *key, size_t len);
    bool setIV(const uint8_t *iv, size_t len);
    void encrypt(uint8_t *output, const uint8_t *input, size_t len);
    void decrypt(uint8_t *output, const uint8_t *input, size_t len);
    void addAuthData(const void *data, size_t len);
    void computeTag(void *tag, size_t len);
    bool checkTag(const void *tag, size_t len);
    void clear();
private:
    ChaCha chacha;
    Poly1305 poly1305;
    struct {
        uint8_t nonce[16];
        uint64_t authSize;
        uint64_t dataSize;
        bool dataStarted;
        uint8_t ivSize;
    } state;
};
#endif
src/modules/Crypto/Cipher.cpp
New file
@@ -0,0 +1,154 @@
/*
 * 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 "Cipher.h"
/**
 * \class Cipher Cipher.h <Cipher.h>
 * \brief Abstract base class for stream ciphers.
 *
 * This class is intended for implementing ciphers that operate on arbitrary
 * amounts of data.  In particular, stream ciphers where the number of
 * bytes that are input to encrypt() or decrypt() is exactly the same as
 * the number of bytes that are output.
 *
 * All of the stream ciphers such as ChaCha inherit directly from this class,
 * together with block cipher modes such as CTR and CFB.
 */
/**
 * \brief Constructs a new cipher object.
 */
Cipher::Cipher()
{
}
/**
 * \brief Destroys this cipher object.
 *
 * Subclasses are responsible for clearing temporary key schedules
 * and other buffers so as to avoid leaking sensitive information.
 *
 * \sa clear()
 */
Cipher::~Cipher()
{
}
/**
 * \fn size_t Cipher::keySize() const
 * \brief Default size of the key for this cipher, in bytes.
 *
 * If the cipher supports variable-sized keys, keySize() indicates the
 * default or recommended key size.  The cipher may support other key sizes.
 *
 * \sa setKey(), ivSize()
 */
/**
 * \fn size_t Cipher::ivSize() const
 * \brief Size of the initialization vector for this cipher, in bytes.
 *
 * If the cipher does not need an initialization vector, this function
 * will return zero.
 */
/**
 * \fn bool Cipher::setKey(const uint8_t *key, size_t len)
 * \brief Sets the key to use for future encryption and decryption operations.
 *
 * \param key The key to use.
 * \param len The length of the key in bytes.
 * \return Returns false if the key length is not supported, or the key
 * is somehow "weak" and unusable by this cipher.
 *
 * Use clear() or the destructor to remove the key and any other sensitive
 * data from the object once encryption or decryption is complete.
 *
 * Calling setKey() resets the cipher.  Any temporary data that was being
 * retained for encrypting partial blocks will be abandoned.
 *
 * \sa keySize(), clear()
 */
/**
 * \fn bool Cipher::setIV(const uint8_t *iv, size_t len)
 * \brief Sets the initialization vector to use for future encryption and
 * decryption operations.
 *
 * \param iv The initialization vector to use.
 * \param len The length of the initialization vector in bytes.
 * \return Returns false if the length is not supported.
 *
 * Initialization vectors should be set before the first call to
 * encrypt() or decrypt() after a setKey() call.  If the initialization
 * vector is changed after encryption or decryption begins,
 * then the behaviour is undefined.
 *
 * \note The IV is not encoded into the output stream by encrypt().
 * The caller is responsible for communicating the IV to the other party.
 *
 * \sa ivSize()
 */
/**
 * \fn void Cipher::encrypt(uint8_t *output, const uint8_t *input, size_t len)
 * \brief Encrypts an input buffer and writes the ciphertext to an
 * output buffer.
 *
 * \param output The output buffer to write to, which may be the same
 * buffer as \a input.  The \a output buffer must have at least as many
 * bytes as the \a input buffer.
 * \param input The input buffer to read from.
 * \param len The number of bytes to encrypt.
 *
 * The encrypt() function can be called multiple times with different
 * regions of the plaintext data.
 *
 * \sa decrypt()
 */
/**
 * \fn void Cipher::decrypt(uint8_t *output, const uint8_t *input, size_t len)
 * \brief Decrypts an input buffer and writes the plaintext to an
 * output buffer.
 *
 * \param output The output buffer to write to, which may be the same
 * buffer as \a input.  The \a output buffer must have at least as many
 * bytes as the \a input buffer.
 * \param input The input buffer to read from.
 * \param len The number of bytes to decrypt.
 *
 * The decrypt() function can be called multiple times with different
 * regions of the ciphertext data.
 *
 * \sa encrypt()
 */
/**
 * \fn void Cipher::clear()
 * \brief Clears all security-sensitive state from this cipher.
 *
 * Security-sensitive information includes key schedules, initialization
 * vectors, and any temporary state that is used by encrypt() or decrypt()
 * which is stored in the cipher itself.
 */
src/modules/Crypto/Cipher.h
New file
@@ -0,0 +1,47 @@
/*
 * 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.
 */
#ifndef CRYPTO_CIPHER_h
#define CRYPTO_CIPHER_h
#include <inttypes.h>
#include <stddef.h>
class Cipher
{
public:
    Cipher();
    virtual ~Cipher();
    virtual size_t keySize() const = 0;
    virtual size_t ivSize() const = 0;
    virtual bool setKey(const uint8_t *key, size_t len) = 0;
    virtual bool setIV(const uint8_t *iv, size_t len) = 0;
    virtual void encrypt(uint8_t *output, const uint8_t *input, size_t len) = 0;
    virtual void decrypt(uint8_t *output, const uint8_t *input, size_t len) = 0;
    virtual void clear() = 0;
};
#endif
src/modules/Crypto/Crypto.cpp
New file
@@ -0,0 +1,114 @@
/*
 * 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 "Crypto.h"
/**
 * \brief Cleans a block of bytes.
 *
 * \param dest The destination block to be cleaned.
 * \param size The size of the destination to be cleaned in bytes.
 *
 * Unlike memset(), this function attempts to prevent the compiler
 * from optimizing away the clear on a memory buffer.
 */
void clean(void *dest, size_t size)
{
    // Force the use of volatile so that we actually clear the memory.
    // Otherwise the compiler might optimise the entire contents of this
    // function away, which will not be secure.
    volatile uint8_t *d = (volatile uint8_t *)dest;
    while (size > 0) {
        *d++ = 0;
        --size;
    }
}
/**
 * \fn void clean(T &var)
 * \brief Template function that cleans a variable.
 *
 * \param var A reference to the variable to clean.
 *
 * The variable will be cleared to all-zeroes in a secure manner.
 * Unlike memset(), this function attempts to prevent the compiler
 * from optimizing away the variable clear.
 */
/**
 * \brief Compares two memory blocks for equality.
 *
 * \param data1 Points to the first memory block.
 * \param data2 Points to the second memory block.
 * \param len The size of the memory blocks in bytes.
 *
 * Unlike memcmp(), this function attempts to compare the two memory blocks
 * in a way that will not reveal the contents in the instruction timing.
 * In particular, this function will not stop early if a byte is different.
 * It will instead continue onto the end of the array.
 */
bool secure_compare(const void *data1, const void *data2, size_t len)
{
    uint8_t result = 0;
    const uint8_t *d1 = (const uint8_t *)data1;
    const uint8_t *d2 = (const uint8_t *)data2;
    while (len > 0) {
        result |= (*d1++ ^ *d2++);
        --len;
    }
    return (bool)((((uint16_t)0x0100) - result) >> 8);
}
/**
 * \brief Calculates the CRC-8 value over an array in memory.
 *
 * \param tag Starting tag to distinguish this calculation.
 * \param data The data to checksum.
 * \param size The number of bytes to checksum.
 * \return The CRC-8 value over the data.
 *
 * This function does not provide any real security.  It is a simple
 * check that seed values have been initialized within EEPROM or Flash.
 * If the CRC-8 check fails, then it is assumed that the EEPROM/Flash
 * contents are invalid and should be re-initialized.
 *
 * Reference: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch4
 */
uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size)
{
    const uint8_t *d = (const uint8_t *)data;
    uint8_t crc = 0xFF ^ tag;
    uint8_t bit;
    while (size > 0) {
        crc ^= *d++;
        for (bit = 0; bit < 8; ++bit) {
            // if (crc & 0x80)
            //     crc = (crc << 1) ^ 0x1D;
            // else
            //     crc = (crc << 1);
            uint8_t generator = (uint8_t)((((int8_t)crc) >> 7) & 0x1D);
            crc = (crc << 1) ^ generator;
        }
        --size;
    }
    return crc;
}
src/modules/Crypto/Crypto.h
New file
@@ -0,0 +1,46 @@
/*
 * 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.
 */
#ifndef CRYPTO_h
#define CRYPTO_h
#include <inttypes.h>
#include <stddef.h>
void clean(void *dest, size_t size);
template <typename T>
inline void clean(T &var)
{
    clean(&var, sizeof(T));
}
bool secure_compare(const void *data1, const void *data2, size_t len);
#if defined(ESP8266)
extern "C" void system_soft_wdt_feed(void);
#define crypto_feed_watchdog() system_soft_wdt_feed()
#else
#define crypto_feed_watchdog() do { ; } while (0)
#endif
#endif
src/modules/Crypto/Curve25519.cpp
New file
@@ -0,0 +1,1610 @@
/*
 * 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 "Curve25519.h"
#include "Crypto.h"
#include "RNG.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
 * \class Curve25519 Curve25519.h <Curve25519.h>
 * \brief Diffie-Hellman key agreement based on the elliptic curve
 * modulo 2^255 - 19.
 *
 * \note The public functions in this class need a substantial amount of
 * stack space to store intermediate results while the curve function is
 * being evaluated.  About 1k of free stack space is recommended for safety.
 *
 * References: http://cr.yp.to/ecdh.html,
 * <a href="http://tools.ietf.org/html/rfc7748">RFC 7748</a>
 *
 * \sa Ed25519
 */
// Global switch to enable/disable AVR inline assembly optimizations.
#if defined(__AVR__)
// Disabled for now - there are issues with newer Arduino compilers.  FIXME
//#define CURVE25519_ASM_AVR 1
#endif
// The overhead of clean() calls in mul(), reduceQuick(), etc can
// add up to a lot of processing time during eval().  Only do such
// cleanups if strict mode has been enabled.  Other implementations
// like curve25519-donna don't do any cleaning at all so the value
// of cleaning up the stack is dubious at best anyway.
#if defined(CURVE25519_STRICT_CLEAN)
#define strict_clean(x)     clean(x)
#else
#define strict_clean(x)     do { ; } while (0)
#endif
/**
 * \brief Evaluates the raw Curve25519 function.
 *
 * \param result The result of evaluating the curve function.
 * \param s The S parameter to the curve function.
 * \param x The X(Q) parameter to the curve function.  If this pointer is
 * NULL then the value 9 is used for \a x.
 *
 * This function is provided to assist with implementating other
 * algorithms with the curve.  Normally applications should use dh1()
 * and dh2() directly instead.
 *
 * \return Returns true if the function was evaluated; false if \a x is
 * not a proper member of the field modulo (2^255 - 19).
 *
 * Reference: <a href="http://tools.ietf.org/html/rfc7748">RFC 7748</a>
 *
 * \sa dh1(), dh2()
 */
bool Curve25519::eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32])
{
    limb_t x_1[NUM_LIMBS_256BIT];
    limb_t x_2[NUM_LIMBS_256BIT];
    limb_t x_3[NUM_LIMBS_256BIT];
    limb_t z_2[NUM_LIMBS_256BIT];
    limb_t z_3[NUM_LIMBS_256BIT];
    limb_t A[NUM_LIMBS_256BIT];
    limb_t B[NUM_LIMBS_256BIT];
    limb_t C[NUM_LIMBS_256BIT];
    limb_t D[NUM_LIMBS_256BIT];
    limb_t E[NUM_LIMBS_256BIT];
    limb_t AA[NUM_LIMBS_256BIT];
    limb_t BB[NUM_LIMBS_256BIT];
    limb_t DA[NUM_LIMBS_256BIT];
    limb_t CB[NUM_LIMBS_256BIT];
    uint8_t mask;
    uint8_t sposn;
    uint8_t select;
    uint8_t swap;
    bool retval;
    // Unpack the "x" argument into the limb representation
    // which also masks off the high bit.  NULL means 9.
    if (x) {
        // x1 = x
        BigNumberUtil::unpackLE(x_1, NUM_LIMBS_256BIT, x, 32);
        x_1[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
    } else {
        memset(x_1, 0, sizeof(x_1));    // x_1 = 9
        x_1[0] = 9;
    }
    // Check that "x" is within the range of the modulo field.
    // We can do this with a reduction - if there was no borrow
    // then the value of "x" was out of range.  Timing is sensitive
    // here so that we don't reveal anything about the value of "x".
    // If there was a reduction, then continue executing the rest
    // of this function with the (now) in-range "x" value and
    // report the failure at the end.
    retval = (bool)(reduceQuick(x_1) & 0x01);
    // Initialize the other temporary variables.
    memset(x_2, 0, sizeof(x_2));        // x_2 = 1
    x_2[0] = 1;
    memset(z_2, 0, sizeof(z_2));        // z_2 = 0
    memcpy(x_3, x_1, sizeof(x_1));      // x_3 = x
    memcpy(z_3, x_2, sizeof(x_2));      // z_3 = 1
    // Iterate over all 255 bits of "s" from the highest to the lowest.
    // We ignore the high bit of the 256-bit representation of "s".
    mask = 0x40;
    sposn = 31;
    swap = 0;
    for (uint8_t t = 255; t > 0; --t) {
        // Conditional swaps on entry to this bit but only if we
        // didn't swap on the previous bit.
        select = s[sposn] & mask;
        swap ^= select;
        cswap(swap, x_2, x_3);
        cswap(swap, z_2, z_3);
        // Evaluate the curve.
        add(A, x_2, z_2);               // A = x_2 + z_2
        square(AA, A);                  // AA = A^2
        sub(B, x_2, z_2);               // B = x_2 - z_2
        square(BB, B);                  // BB = B^2
        sub(E, AA, BB);                 // E = AA - BB
        add(C, x_3, z_3);               // C = x_3 + z_3
        sub(D, x_3, z_3);               // D = x_3 - z_3
        mul(DA, D, A);                  // DA = D * A
        mul(CB, C, B);                  // CB = C * B
        add(x_3, DA, CB);               // x_3 = (DA + CB)^2
        square(x_3, x_3);
        sub(z_3, DA, CB);               // z_3 = x_1 * (DA - CB)^2
        square(z_3, z_3);
        mul(z_3, z_3, x_1);
        mul(x_2, AA, BB);               // x_2 = AA * BB
        mulA24(z_2, E);                 // z_2 = E * (AA + a24 * E)
        add(z_2, z_2, AA);
        mul(z_2, z_2, E);
        // Move onto the next lower bit of "s".
        mask >>= 1;
        if (!mask) {
            --sposn;
            mask = 0x80;
            swap = select << 7;
        } else {
            swap = select >> 1;
        }
    }
    // Final conditional swaps.
    cswap(swap, x_2, x_3);
    cswap(swap, z_2, z_3);
    // Compute x_2 * (z_2 ^ (p - 2)) where p = 2^255 - 19.
    recip(z_3, z_2);
    mul(x_2, x_2, z_3);
    // Pack the result into the return array.
    BigNumberUtil::packLE(result, 32, x_2, NUM_LIMBS_256BIT);
    // Clean up and exit.
    clean(x_1);
    clean(x_2);
    clean(x_3);
    clean(z_2);
    clean(z_3);
    clean(A);
    clean(B);
    clean(C);
    clean(D);
    clean(E);
    clean(AA);
    clean(BB);
    clean(DA);
    clean(CB);
    return retval;
}
/**
 * \brief Performs phase 1 of a Diffie-Hellman key exchange using Curve25519.
 *
 * \param k The key value to send to the other party as part of the exchange.
 * \param f The generated secret value for this party.  This must not be
 * transmitted to any party or stored in permanent storage.  It only needs
 * to be kept in memory until dh2() is called.
 *
 * The \a f value is generated with \link RNGClass::rand() RNG.rand()\endlink.
 * It is the caller's responsibility to ensure that the global random number
 * pool has sufficient entropy to generate the 32 bytes of \a f safely
 * before calling this function.
 *
 * The following example demonstrates how to perform a full Diffie-Hellman
 * key exchange using dh1() and dh2():
 *
 * \code
 * uint8_t f[32];
 * uint8_t k[32];
 *
 * // Generate the secret value "f" and the public value "k".
 * Curve25519::dh1(k, f);
 *
 * // Send "k" to the other party.
 * ...
 *
 * // Read the "k" value that the other party sent to us.
 * ...
 *
 * // Generate the shared secret in "k" using the previous secret value "f".
 * if (!Curve25519::dh2(k, f)) {
 *     // The received "k" value was invalid - abort the session.
 *     ...
 * }
 *
 * // The "k" value can now be used to generate session keys for encryption.
 * ...
 * \endcode
 *
 * Reference: <a href="http://tools.ietf.org/html/rfc7748">RFC 7748</a>
 *
 * \sa dh2()
 */
void Curve25519::dh1(uint8_t k[32], uint8_t f[32])
{
    do {
        // Generate a random "f" value and then adjust the value to make
        // it valid as an "s" value for eval().  According to the specification
        // we need to mask off the 3 right-most bits of f[0], mask off the
        // left-most bit of f[31], and set the second to left-most bit of f[31].
        RNG.rand(f, 32);
        f[0] &= 0xF8;
        f[31] = (f[31] & 0x7F) | 0x40;
        // Evaluate the curve function: k = Curve25519::eval(f, 9).
        // We pass NULL to eval() to indicate the value 9.  There is no
        // need to check the return value from eval() because we know
        // that 9 is a valid field element.
        eval(k, f, 0);
        // If "k" is weak for contributory behaviour then reject it,
        // generate another "f" value, and try again.  This case is
        // highly unlikely but we still perform the check just in case.
    } while (isWeakPoint(k));
}
/**
 * \brief Performs phase 2 of a Diffie-Hellman key exchange using Curve25519.
 *
 * \param k On entry, this is the key value that was received from the other
 * party as part of the exchange.  On exit, this will be the shared secret.
 * \param f The secret value for this party that was generated by dh1().
 * The \a f value will be destroyed by this function.
 *
 * \return Returns true if the key exchange was successful, or false if
 * the \a k value is invalid.
 *
 * Reference: <a href="http://tools.ietf.org/html/rfc7748">RFC 7748</a>
 *
 * \sa dh1()
 */
bool Curve25519::dh2(uint8_t k[32], uint8_t f[32])
{
    uint8_t weak;
    // Evaluate the curve function: k = Curve25519::eval(f, k).
    // If "k" is weak for contributory behaviour before or after
    // the curve evaluation, then fail the exchange.  For safety
    // we perform every phase of the weak checks even if we could
    // bail out earlier so that the execution takes the same
    // amount of time for weak and non-weak "k" values.
    weak  = isWeakPoint(k);                     // Is "k" weak before?
    weak |= ((eval(k, f, k) ^ 0x01) & 0x01);    // Is "k" weak during?
    weak |= isWeakPoint(k);                     // Is "k" weak after?
    clean(f, 32);
    return (bool)((weak ^ 0x01) & 0x01);
}
/**
 * \brief Determines if a Curve25519 point is weak for contributory behaviour.
 *
 * \param k The point to check.
 * \return Returns 1 if \a k is weak for contributory behavior or
 * returns zero if \a k is not weak.
 */
uint8_t Curve25519::isWeakPoint(const uint8_t k[32])
{
    // List of weak points from http://cr.yp.to/ecdh.html
    // That page lists some others but they are variants on these
    // of the form "point + i * (2^255 - 19)" for i = 0, 1, 2.
    // Here we mask off the high bit and eval() catches the rest.
    static const uint8_t points[5][32] PROGMEM = {
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        {0xE0, 0xEB, 0x7A, 0x7C, 0x3B, 0x41, 0xB8, 0xAE,
         0x16, 0x56, 0xE3, 0xFA, 0xF1, 0x9F, 0xC4, 0x6A,
         0xDA, 0x09, 0x8D, 0xEB, 0x9C, 0x32, 0xB1, 0xFD,
         0x86, 0x62, 0x05, 0x16, 0x5F, 0x49, 0xB8, 0x00},
        {0x5F, 0x9C, 0x95, 0xBC, 0xA3, 0x50, 0x8C, 0x24,
         0xB1, 0xD0, 0xB1, 0x55, 0x9C, 0x83, 0xEF, 0x5B,
         0x04, 0x44, 0x5C, 0xC4, 0x58, 0x1C, 0x8E, 0x86,
         0xD8, 0x22, 0x4E, 0xDD, 0xD0, 0x9F, 0x11, 0x57},
        {0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F}
    };
    // Check each of the weak points in turn.  We perform the
    // comparisons carefully so as not to reveal the value of "k"
    // in the instruction timing.  If "k" is indeed weak then
    // we still check everything so as not to reveal which
    // weak point it is.
    uint8_t result = 0;
    for (uint8_t posn = 0; posn < 5; ++posn) {
        const uint8_t *point = points[posn];
        uint8_t check = (pgm_read_byte(&(point[31])) ^ k[31]) & 0x7F;
        for (uint8_t index = 31; index > 0; --index)
            check |= (pgm_read_byte(&(point[index - 1])) ^ k[index - 1]);
        result |= (uint8_t)((((uint16_t)0x0100) - check) >> 8);
    }
    // The "result" variable will be non-zero if there was a match.
    return result;
}
/**
 * \brief Reduces a number modulo 2^255 - 19.
 *
 * \param result The array that will contain the result when the
 * function exits.  Must be NUM_LIMBS_256BIT limbs in size.
 * \param x The number to be reduced, which must be NUM_LIMBS_512BIT
 * limbs in size and less than or equal to square(2^255 - 19 - 1).
 * This array will be modified by the reduction process.
 * \param size The size of the high order half of \a x.  This indicates
 * the size of \a x in limbs.  If it is shorter than NUM_LIMBS_256BIT
 * then the reduction can be performed quicker.
 */
void Curve25519::reduce(limb_t *result, limb_t *x, uint8_t size)
{
    /*
    Note: This explaination is best viewed with a UTF-8 text viewer.
    To help explain what this function is doing, the following describes
    how to efficiently compute reductions modulo a base of the form (2ⁿ - b)
    where b is greater than zero and (b + 1)² <= 2ⁿ.
    Here we are interested in reducing the result of multiplying two
    numbers that are less than or equal to (2ⁿ - b - 1).  That is,
    multiplying numbers that have already been reduced.
    Given some x less than or equal to (2ⁿ - b - 1)², we want to find a
    y less than (2ⁿ - b) such that:
        y ≡ x mod (2ⁿ - b)
    We know that for all integer values of k >= 0:
        y ≡ x - k * (2ⁿ - b)
          ≡ x - k * 2ⁿ + k * b
    In our case we choose k = ⌊x / 2ⁿ⌋ and then let:
        w = (x mod 2ⁿ) + ⌊x / 2ⁿ⌋ * b
    The value w will either be the answer y or y can be obtained by
    repeatedly subtracting (2ⁿ - b) from w until it is less than (2ⁿ - b).
    At most b subtractions will be required.
    In our case b is 19 which is more subtractions than we would like to do,
    but we can handle that by performing the above reduction twice and then
    performing a single trial subtraction:
        w = (x mod 2ⁿ) + ⌊x / 2ⁿ⌋ * b
        y = (w mod 2ⁿ) + ⌊w / 2ⁿ⌋ * b
        if y >= (2ⁿ - b)
            y -= (2ⁿ - b)
    The value y is the answer we want for reducing x modulo (2ⁿ - b).
    */
#if !defined(CURVE25519_ASM_AVR)
    dlimb_t carry;
    uint8_t posn;
    // Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
    // either produce the answer we want or it will produce a
    // value of the form "answer + j * (2^255 - 19)".
    carry = ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
    x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
    for (posn = 0; posn < size; ++posn) {
        carry += ((dlimb_t)(x[posn + NUM_LIMBS_256BIT])) * 38U;
        carry += x[posn];
        x[posn] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    if (size < NUM_LIMBS_256BIT) {
        // The high order half of the number is short; e.g. for mulA24().
        // Propagate the carry through the rest of the low order part.
        for (posn = size; posn < NUM_LIMBS_256BIT; ++posn) {
            carry += x[posn];
            x[posn] = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
    }
    // The "j" value may still be too large due to the final carry-out.
    // We must repeat the reduction.  If we already have the answer,
    // then this won't do any harm but we must still do the calculation
    // to preserve the overall timing.
    carry *= 38U;
    carry += ((dlimb_t)(x[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1))) * 19U;
    x[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        carry += x[posn];
        x[posn] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // At this point "x" will either be the answer or it will be the
    // answer plus (2^255 - 19).  Perform a trial subtraction which
    // is equivalent to adding 19 and subtracting 2^255.  We put the
    // trial answer into the top-most limbs of the original "x" array.
    // We add 19 here; the subtraction of 2^255 occurs in the next step.
    carry = 19U;
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        carry += x[posn];
        x[posn + NUM_LIMBS_256BIT] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // If there was a borrow, then the bottom-most limbs of "x" are the
    // correct answer.  If there was no borrow, then the top-most limbs
    // of "x" are the correct answer.  Select the correct answer but do
    // it in a way that instruction timing will not reveal which value
    // was selected.  Borrow will occur if the high bit of the previous
    // result is 0: turn the high bit into a selection mask.
    limb_t mask = (limb_t)(((slimb_t)(x[NUM_LIMBS_512BIT - 1])) >> (LIMB_BITS - 1));
    limb_t nmask = ~mask;
    x[NUM_LIMBS_512BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        result[posn] = (x[posn] & nmask) | (x[posn + NUM_LIMBS_256BIT] & mask);
    }
#else
    __asm__ __volatile__ (
        // Calculate (x mod 2^255) + ((x / 2^255) * 19) which will
        // either produce the answer we want or it will produce a
        // value of the form "answer + j * (2^255 - 19)".
        "ldd r24,Z+31\n"                // Extract the high bit of x[31]
        "mov r25,r24\n"                 // and mask it off
        "andi r25,0x7F\n"
        "std Z+31,r25\n"
        "lsl r24\n"                     // carry = high bit * 19
        "mov r24,__zero_reg__\n"
        "sbc r24,__zero_reg__\n"
        "andi r24,19\n"
        "mov r25,%1\n"                  // load "size" into r25
        "ldi r23,38\n"                  // r23 = 38
        "mov r22,__zero_reg__\n"        // r22 = 0 (we're about to destroy r1)
        "1:\n"
        "ld r16,Z\n"                    // r16 = x[0]
        "ldd r17,Z+32\n"                // r17 = x[32]
        "mul r17,r23\n"                 // r0:r1 = r17 * 38
        "add r0,r24\n"                  // r0:r1 += carry
        "adc r1,r22\n"
        "add r0,r16\n"                  // r0:r1 += r16
        "adc r1,r22\n"
        "st Z+,r0\n"                    // *x++ = r0
        "mov r24,r1\n"                  // carry = r1
        "dec r25\n"                     // if (--r25 != 0) loop
        "brne 1b\n"
        // If the size is short, then we need to continue propagating carries.
        "ldi r25,32\n"
        "cp %1,r25\n"
        "breq 3f\n"
        "sub r25,%1\n"
        "ld __tmp_reg__,Z\n"
        "add __tmp_reg__,r24\n"
        "st Z+,__tmp_reg__\n"
        "dec r25\n"
        "2:\n"
        "ld __tmp_reg__,Z\n"            // *x++ += carry
        "adc __tmp_reg__,r22\n"
        "st Z+,__tmp_reg__\n"
        "dec r25\n"
        "brne 2b\n"
        "mov r24,r22\n"                 // put the carry back into r24
        "adc r24,r22\n"
        "3:\n"
        "sbiw r30,32\n"                 // Point Z back to the start of "x"
        // The "j" value may still be too large due to the final carry-out.
        // We must repeat the reduction.  If we already have the answer,
        // then this won't do any harm but we must still do the calculation
        // to preserve the overall timing.
        "mul r24,r23\n"                 // carry *= 38
        "ldd r24,Z+31\n"                // Extract the high bit of x[31]
        "mov r25,r24\n"                 // and mask it off
        "andi r25,0x7F\n"
        "std Z+31,r25\n"
        "lsl r24\n"                     // carry += high bit * 19
        "mov r24,r22\n"
        "sbc r24,r22\n"
        "andi r24,19\n"
        "add r0,r24\n"
        "adc r1,r22\n"                  // 9-bit carry is now in r0:r1
        // Propagate the carry through the rest of x.
        "ld r24,Z\n"                    // x[0]
        "add r0,r24\n"
        "adc r1,r22\n"
        "st Z+,r0\n"
        "ld r24,Z\n"                    // x[1]
        "add r1,r24\n"
        "st Z+,r1\n"
        "ldi r25,30\n"                  // x[2..31]
        "4:\n"
        "ld r24,Z\n"
        "adc r24,r22\n"
        "st Z+,r24\n"
        "dec r25\n"
        "brne 4b\n"
        "sbiw r30,32\n"                 // Point Z back to the start of "x"
        // We destroyed __zero_reg__ (r1) above, so restore its zero value.
        "mov __zero_reg__,r22\n"
        // At this point "x" will either be the answer or it will be the
        // answer plus (2^255 - 19).  Perform a trial subtraction which
        // is equivalent to adding 19 and subtracting 2^255.  We put the
        // trial answer into the top-most limbs of the original "x" array.
        // We add 19 here; the subtraction of 2^255 occurs in the next step.
        "ldi r24,8\n"               // Loop counter.
        "ldi r25,19\n"              // carry = 19
        "5:\n"
        "ld r16,Z+\n"               // r16:r19:carry = *xx++ + carry
        "ld r17,Z+\n"
        "ld r18,Z+\n"
        "ld r19,Z+\n"
        "add r16,r25\n"             // r16:r19:carry += carry
        "adc r17,__zero_reg__\n"
        "adc r18,__zero_reg__\n"
        "adc r19,__zero_reg__\n"
        "mov r25,__zero_reg__\n"
        "adc r25,r25\n"
        "std Z+28,r16\n"            // *tt++ = r16:r19
        "std Z+29,r17\n"
        "std Z+30,r18\n"
        "std Z+31,r19\n"
        "dec r24\n"
        "brne 5b\n"
        // Subtract 2^255 from x[32..63] which is equivalent to extracting
        // the top bit and then masking it off.  If the top bit is zero
        // then a borrow has occurred and this isn't the answer we want.
        "mov r25,r19\n"
        "andi r19,0x7F\n"
        "std Z+31,r19\n"
        "lsl r25\n"
        "mov r25,__zero_reg__\n"
        "sbc r25,__zero_reg__\n"
        // At this point, r25 is 0 if the original x[0..31] is the answer
        // we want, or 0xFF if x[32..63] is the answer we want.  Essentially
        // we need to do a conditional move of either x[0..31] or x[32..63]
        // into "result".
        "sbiw r30,32\n"             // Point Z back to x[0].
        "ldi r24,8\n"
        "6:\n"
        "ldd r16,Z+32\n"
        "ldd r17,Z+33\n"
        "ldd r18,Z+34\n"
        "ldd r19,Z+35\n"
        "ld r20,Z+\n"
        "ld r21,Z+\n"
        "ld r22,Z+\n"
        "ld r23,Z+\n"
        "eor r16,r20\n"
        "eor r17,r21\n"
        "eor r18,r22\n"
        "eor r19,r23\n"
        "and r16,r25\n"
        "and r17,r25\n"
        "and r18,r25\n"
        "and r19,r25\n"
        "eor r20,r16\n"
        "eor r21,r17\n"
        "eor r22,r18\n"
        "eor r23,r19\n"
        "st X+,r20\n"
        "st X+,r21\n"
        "st X+,r22\n"
        "st X+,r23\n"
        "dec r24\n"
        "brne 6b\n"
        : : "z"(x), "r"((uint8_t)(size * sizeof(limb_t))), "x"(result)
        : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
          "r24", "r25"
    );
#endif
}
/**
 * \brief Quickly reduces a number modulo 2^255 - 19.
 *
 * \param x The number to be reduced, which must be NUM_LIMBS_256BIT
 * limbs in size and less than or equal to 2 * (2^255 - 19 - 1).
 * \return Zero if \a x was greater than or equal to (2^255 - 19).
 *
 * The answer is also put into \a x and will consist of NUM_LIMBS_256BIT limbs.
 *
 * This function is intended for reducing the result of additions where
 * the caller knows that \a x is within the described range.  A single
 * trial subtraction is all that is needed to reduce the number.
 */
limb_t Curve25519::reduceQuick(limb_t *x)
{
#if !defined(CURVE25519_ASM_AVR)
    limb_t temp[NUM_LIMBS_256BIT];
    dlimb_t carry;
    uint8_t posn;
    limb_t *xx;
    limb_t *tt;
    // Perform a trial subtraction of (2^255 - 19) from "x" which is
    // equivalent to adding 19 and subtracting 2^255.  We add 19 here;
    // the subtraction of 2^255 occurs in the next step.
    carry = 19U;
    xx = x;
    tt = temp;
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        carry += *xx++;
        *tt++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // If there was a borrow, then the original "x" is the correct answer.
    // If there was no borrow, then "temp" is the correct answer.  Select the
    // correct answer but do it in a way that instruction timing will not
    // reveal which value was selected.  Borrow will occur if the high bit
    // of "temp" is 0: turn the high bit into a selection mask.
    limb_t mask = (limb_t)(((slimb_t)(temp[NUM_LIMBS_256BIT - 1])) >> (LIMB_BITS - 1));
    limb_t nmask = ~mask;
    temp[NUM_LIMBS_256BIT - 1] &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
    xx = x;
    tt = temp;
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        *xx = ((*xx) & nmask) | ((*tt++) & mask);
        ++xx;
    }
    // Clean up "temp".
    strict_clean(temp);
    // Return a zero value if we actually subtracted (2^255 - 19) from "x".
    return nmask;
#else // CURVE25519_ASM_AVR
    limb_t temp[NUM_LIMBS_256BIT];
    uint8_t result;
    __asm__ __volatile__ (
        // Subtract (2^255 - 19) from "x", which is the same as adding 19
        // and then subtracting 2^255.
        "ldi r24,8\n"               // Loop counter.
        "ldi r25,19\n"              // carry = 19
        "1:\n"
        "ld r16,Z+\n"               // r16:r19:carry = *xx++ + carry
        "ld r17,Z+\n"
        "ld r18,Z+\n"
        "ld r19,Z+\n"
        "add r16,r25\n"             // r16:r19:carry += carry
        "adc r17,__zero_reg__\n"
        "adc r18,__zero_reg__\n"
        "adc r19,__zero_reg__\n"
        "mov r25,__zero_reg__\n"
        "adc r25,r25\n"
        "st X+,r16\n"               // *tt++ = r16:r19
        "st X+,r17\n"
        "st X+,r18\n"
        "st X+,r19\n"
        "dec r24\n"
        "brne 1b\n"
        // Subtract 2^255 from "temp" which is equivalent to extracting
        // the top bit and then masking it off.  If the top bit is zero
        // then a borrow has occurred and this isn't the answer we want.
        "mov r25,r19\n"
        "andi r19,0x7F\n"
        "st -X,r19\n"
        "lsl r25\n"
        "mov r25,__zero_reg__\n"
        "sbc r25,__zero_reg__\n"
        // At this point, r25 is 0 if the original "x" is the answer
        // we want, or 0xFF if "temp" is the answer we want.  Essentially
        // we need to do a conditional move of "temp" into "x".
        "sbiw r26,31\n"             // Point X back to the start of "temp".
        "sbiw r30,32\n"             // Point Z back to the start of "x".
        "ldi r24,8\n"
        "2:\n"
        "ld r16,X+\n"
        "ld r17,X+\n"
        "ld r18,X+\n"
        "ld r19,X+\n"
        "ld r20,Z\n"
        "ldd r21,Z+1\n"
        "ldd r22,Z+2\n"
        "ldd r23,Z+3\n"
        "eor r16,r20\n"
        "eor r17,r21\n"
        "eor r18,r22\n"
        "eor r19,r23\n"
        "and r16,r25\n"
        "and r17,r25\n"
        "and r18,r25\n"
        "and r19,r25\n"
        "eor r20,r16\n"
        "eor r21,r17\n"
        "eor r22,r18\n"
        "eor r23,r19\n"
        "st Z+,r20\n"
        "st Z+,r21\n"
        "st Z+,r22\n"
        "st Z+,r23\n"
        "dec r24\n"
        "brne 2b\n"
        "mov %0,r25\n"
        : "=r"(result)
        : "x"(temp), "z"(x)
        : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
          "r24", "r25"
    );
    strict_clean(temp);
    return result;
#endif // CURVE25519_ASM_AVR
}
/**
 * \brief Multiplies two 256-bit values to produce a 512-bit result.
 *
 * \param result The result, which must be NUM_LIMBS_512BIT limbs in size
 * and must not overlap with \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_256BIT
 * limbs in size.
 * \param y The second value to multiply, which must be NUM_LIMBS_256BIT
 * limbs in size.
 *
 * \sa mul()
 */
void Curve25519::mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y)
{
#if !defined(CURVE25519_ASM_AVR)
    uint8_t i, j;
    dlimb_t carry;
    limb_t word;
    const limb_t *yy;
    limb_t *rr;
    // Multiply the lowest word of x by y.
    carry = 0;
    word = x[0];
    yy = y;
    rr = result;
    for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
        carry += ((dlimb_t)(*yy++)) * word;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    *rr = (limb_t)carry;
    // Multiply and add the remaining words of x by y.
    for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
        word = x[i];
        carry = 0;
        yy = y;
        rr = result + i;
        for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
            carry += ((dlimb_t)(*yy++)) * word;
            carry += *rr;
            *rr++ = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        *rr = (limb_t)carry;
    }
#else
    __asm__ __volatile__ (
        // Save Y and copy the "result" pointer into it.
        "push r28\n"
        "push r29\n"
        "mov r28,%A2\n"
        "mov r29,%B2\n"
        // Multiply the first byte of "x" by y[0..31].
        "ldi r25,8\n"               // loop 8 times: 4 bytes of y each time
        "clr r24\n"                 // carry = 0
        "clr r22\n"                 // r22 = 0 to replace __zero_reg__
        "ld r23,X+\n"               // r23 = *x++
        "1:\n"
        "ld r16,Z\n"                // r16 = y[0]
        "mul r16,r23\n"             // r8:r9 = y[0] * r23
        "movw r8,r0\n"
        "ldd r16,Z+2\n"             // r16 = y[2]
        "mul r16,r23\n"             // r10:r11 = y[2] * r23
        "movw r10,r0\n"
        "ldd r16,Z+1\n"             // r16 = y[1]
        "mul r16,r23\n"             // r9:r10:r11 += y[1] * r23
        "add r9,r0\n"
        "adc r10,r1\n"
        "adc r11,r22\n"
        "ldd r16,Z+3\n"             // r16 = y[3]
        "mul r16,r23\n"             // r11:r1 += y[3] * r23
        "add r11,r0\n"
        "adc r1,r22\n"
        "add r8,r24\n"              // r8:r9:r10:r11:r1 += carry
        "adc r9,r22\n"
        "adc r10,r22\n"
        "adc r11,r22\n"
        "adc r1,r22\n"
        "mov r24,r1\n"              // carry = r1
        "st Y+,r8\n"                // *rr++ = r8:r9:r10:r11
        "st Y+,r9\n"
        "st Y+,r10\n"
        "st Y+,r11\n"
        "adiw r30,4\n"
        "dec r25\n"
        "brne 1b\n"
        "st Y+,r24\n"               // *rr++ = carry
        "sbiw r28,32\n"             // rr -= 32
        "sbiw r30,32\n"             // Point Z back to the start of y
        // Multiply and add the remaining bytes of "x" by y[0..31].
        "ldi r21,31\n"              // 31 more bytes of x to go.
        "2:\n"
        "ldi r25,8\n"               // loop 8 times: 4 bytes of y each time
        "clr r24\n"                 // carry = 0
        "ld r23,X+\n"               // r23 = *x++
        "3:\n"
        "ld r16,Z\n"                // r16 = y[0]
        "mul r16,r23\n"             // r8:r9 = y[0] * r23
        "movw r8,r0\n"
        "ldd r16,Z+2\n"             // r16 = y[2]
        "mul r16,r23\n"             // r10:r11 = y[2] * r23
        "movw r10,r0\n"
        "ldd r16,Z+1\n"             // r16 = y[1]
        "mul r16,r23\n"             // r9:r10:r11 += y[1] * r23
        "add r9,r0\n"
        "adc r10,r1\n"
        "adc r11,r22\n"
        "ldd r16,Z+3\n"             // r16 = y[3]
        "mul r16,r23\n"             // r11:r1 += y[3] * r23
        "add r11,r0\n"
        "adc r1,r22\n"
        "add r8,r24\n"              // r8:r9:r10:r11:r1 += carry
        "adc r9,r22\n"
        "adc r10,r22\n"
        "adc r11,r22\n"
        "adc r1,r22\n"
        "ld r16,Y\n"                // r8:r9:r10:r11:r1 += rr[0..3]
        "add r8,r16\n"
        "ldd r16,Y+1\n"
        "adc r9,r16\n"
        "ldd r16,Y+2\n"
        "adc r10,r16\n"
        "ldd r16,Y+3\n"
        "adc r11,r16\n"
        "adc r1,r22\n"
        "mov r24,r1\n"              // carry = r1
        "st Y+,r8\n"                // *rr++ = r8:r9:r10:r11
        "st Y+,r9\n"
        "st Y+,r10\n"
        "st Y+,r11\n"
        "adiw r30,4\n"
        "dec r25\n"
        "brne 3b\n"
        "st Y+,r24\n"               // *r++ = carry
        "sbiw r28,32\n"             // rr -= 32
        "sbiw r30,32\n"             // Point Z back to the start of y
        "dec r21\n"
        "brne 2b\n"
        // Restore Y and __zero_reg__.
        "pop r29\n"
        "pop r28\n"
        "clr __zero_reg__\n"
        : : "x"(x), "z"(y), "r"(result)
        : "r8", "r9", "r10", "r11", "r16", "r20", "r21", "r22",
          "r23", "r24", "r25"
    );
#endif
}
/**
 * \brief Multiplies two values and then reduces the result modulo 2^255 - 19.
 *
 * \param result The result, which must be NUM_LIMBS_256BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_256BIT limbs
 * in size and less than 2^255 - 19.
 * \param y The second value to multiply, which must be NUM_LIMBS_256BIT limbs
 * in size and less than 2^255 - 19.  This can be the same array as \a x.
 */
void Curve25519::mul(limb_t *result, const limb_t *x, const limb_t *y)
{
    limb_t temp[NUM_LIMBS_512BIT];
    mulNoReduce(temp, x, y);
    reduce(result, temp, NUM_LIMBS_256BIT);
    strict_clean(temp);
    crypto_feed_watchdog();
}
/**
 * \fn void Curve25519::square(limb_t *result, const limb_t *x)
 * \brief Squares a value and then reduces it modulo 2^255 - 19.
 *
 * \param result The result, which must be NUM_LIMBS_256BIT limbs in size and
 * can be the same array as \a x.
 * \param x The value to square, which must be NUM_LIMBS_256BIT limbs in size
 * and less than 2^255 - 19.
 */
/**
 * \brief Multiplies a value by the a24 constant and then reduces the result
 * modulo 2^255 - 19.
 *
 * \param result The result, which must be NUM_LIMBS_256BIT limbs in size
 * and can be the same array as \a x.
 * \param x The value to multiply by a24, which must be NUM_LIMBS_256BIT
 * limbs in size and less than 2^255 - 19.
 */
void Curve25519::mulA24(limb_t *result, const limb_t *x)
{
#if !defined(CURVE25519_ASM_AVR)
    // The constant a24 = 121665 (0x1DB41) as a limb array.
#if BIGNUMBER_LIMB_8BIT
    static limb_t const a24[3] PROGMEM = {0x41, 0xDB, 0x01};
#elif BIGNUMBER_LIMB_16BIT
    static limb_t const a24[2] PROGMEM = {0xDB41, 0x0001};
#elif BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
    static limb_t const a24[1] PROGMEM = {0x0001DB41};
#else
    #error "limb_t must be 8, 16, 32, or 64 bits in size"
#endif
    #define NUM_A24_LIMBS   (sizeof(a24) / sizeof(limb_t))
    // Multiply the lowest limb of a24 by x and zero-extend into the result.
    limb_t temp[NUM_LIMBS_512BIT];
    uint8_t i, j;
    dlimb_t carry = 0;
    limb_t word = pgm_read_limb(&(a24[0]));
    const limb_t *xx = x;
    limb_t *tt = temp;
    for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
        carry += ((dlimb_t)(*xx++)) * word;
        *tt++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    *tt = (limb_t)carry;
    // Multiply and add the remaining limbs of a24.
    for (i = 1; i < NUM_A24_LIMBS; ++i) {
        word = pgm_read_limb(&(a24[i]));
        carry = 0;
        xx = x;
        tt = temp + i;
        for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
            carry += ((dlimb_t)(*xx++)) * word;
            carry += *tt;
            *tt++ = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        *tt = (limb_t)carry;
    }
#else
    limb_t temp[NUM_LIMBS_512BIT];
    #define NUM_A24_LIMBS   ((3 + sizeof(limb_t) - 1) / sizeof(limb_t))
    __asm__ __volatile__ (
        // Load the two low bytes of a24 into r16 and r17.
        // The third byte is 0x01 which we can deal with implicitly.
        "ldi r16,0x41\n"
        "ldi r17,0xDB\n"
        // Iterate over the bytes of "x" and multiply each with a24.
        "ldi r25,32\n"              // 32 bytes in "x"
        "clr r22\n"                 // r22 = 0
        "clr r18\n"                 // r18:r19:r11 = 0 (carry)
        "clr r19\n"
        "clr r11\n"
        "1:\n"
        "ld r21,X+\n"               // r21 = *x++
        "mul r21,r16\n"             // r8:r9 = r21 * a24[0]
        "movw r8,r0\n"
        "mul r21,r17\n"             // r9:r1 += r21 * a24[1]
        "add r9,r0\n"
        "adc r1,r21\n"              // r1:r10 += r21 * a24[2] (implicitly 1)
        "mov r10,r22\n"
        "adc r10,r22\n"
        "add r8,r18\n"              // r8:r9:r1:r10 += carry
        "adc r9,r19\n"
        "adc r1,r11\n"
        "adc r10,r22\n"
        "st Z+,r8\n"                // *tt++ = r8
        "mov r18,r9\n"              // carry = r9:r1:r10
        "mov r19,r1\n"
        "mov r11,r10\n"
        "dec r25\n"
        "brne 1b\n"
        "st Z,r18\n"                // *tt = carry
        "std Z+1,r19\n"
        "std Z+2,r11\n"
#if BIGNUMBER_LIMB_16BIT || BIGNUMBER_LIMB_32BIT
        "std Z+3,r22\n"             // Zero pad to a limb boundary
#endif
        // Restore __zero_reg__
        "clr __zero_reg__\n"
        : : "x"(x), "z"(temp)
        : "r8", "r9", "r10", "r11", "r16", "r17", "r18", "r19",
          "r20", "r21", "r22", "r25"
    );
#endif
    // Reduce the intermediate result modulo 2^255 - 19.
    reduce(result, temp, NUM_A24_LIMBS);
    strict_clean(temp);
}
/**
 * \brief Multiplies two values and then reduces the result modulo 2^255 - 19,
 * where one of the values is in program memory.
 *
 * \param result The result, which must be NUM_LIMBS_256BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_256BIT limbs
 * in size and less than 2^255 - 19.
 * \param y The second value to multiply, which must be NUM_LIMBS_256BIT limbs
 * in size and less than 2^255 - 19.  This array must be in program memory.
 */
void Curve25519::mul_P(limb_t *result, const limb_t *x, const limb_t *y)
{
    limb_t temp[NUM_LIMBS_512BIT];
    uint8_t i, j;
    dlimb_t carry;
    limb_t word;
    const limb_t *xx;
    limb_t *tt;
    // Multiply the lowest word of y by x.
    carry = 0;
    word = pgm_read_limb(&(y[0]));
    xx = x;
    tt = temp;
    for (i = 0; i < NUM_LIMBS_256BIT; ++i) {
        carry += ((dlimb_t)(*xx++)) * word;
        *tt++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    *tt = (limb_t)carry;
    // Multiply and add the remaining words of y by x.
    for (i = 1; i < NUM_LIMBS_256BIT; ++i) {
        word = pgm_read_limb(&(y[i]));
        carry = 0;
        xx = x;
        tt = temp + i;
        for (j = 0; j < NUM_LIMBS_256BIT; ++j) {
            carry += ((dlimb_t)(*xx++)) * word;
            carry += *tt;
            *tt++ = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        *tt = (limb_t)carry;
    }
    // Reduce the intermediate result modulo 2^255 - 19.
    reduce(result, temp, NUM_LIMBS_256BIT);
    strict_clean(temp);
}
/**
 * \brief Adds two values and then reduces the result modulo 2^255 - 19.
 *
 * \param result The result, which must be NUM_LIMBS_256BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_256BIT
 * limbs in size and less than 2^255 - 19.
 * \param y The second value to multiply, which must be NUM_LIMBS_256BIT
 * limbs in size and less than 2^255 - 19.
 */
void Curve25519::add(limb_t *result, const limb_t *x, const limb_t *y)
{
#if !defined(CURVE25519_ASM_AVR)
    dlimb_t carry = 0;
    uint8_t posn;
    limb_t *rr = result;
    // Add the two arrays to obtain the intermediate result.
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        carry += *x++;
        carry += *y++;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
#else // CURVE25519_ASM_AVR
    __asm__ __volatile__ (
        // Save Y and copy the "result" pointer into it.
        "push r28\n"
        "push r29\n"
        "mov r28,%A2\n"
        "mov r29,%B2\n"
        // Unroll the loop to operate on 4 bytes at a time (8 iterations).
        "ldi r24,8\n"               // Loop counter.
        "clr r25\n"                 // carry = 0
        "1:\n"
        "ld r16,X+\n"               // r16:r19 = *x++
        "ld r17,X+\n"
        "ld r18,X+\n"
        "ld r19,X+\n"
        "ld r20,Z+\n"               // r20:r23 = *y++
        "ld r21,Z+\n"
        "ld r22,Z+\n"
        "ld r23,Z+\n"
        "add r16,r25\n"             // r16:r19:carry += carry
        "adc r17,__zero_reg__\n"
        "adc r18,__zero_reg__\n"
        "adc r19,__zero_reg__\n"
        "mov r25,__zero_reg__\n"
        "adc r25,r25\n"
        "add r16,r20\n"             // r16:r19:carry += r20:r23
        "adc r17,r21\n"
        "adc r18,r22\n"
        "adc r19,r23\n"
        "adc r25,__zero_reg__\n"
        "st Y+,r16\n"               // *rr++ = r16:r23
        "st Y+,r17\n"
        "st Y+,r18\n"
        "st Y+,r19\n"
        "dec r24\n"
        "brne 1b\n"
        // Restore Y.
        "pop r29\n"
        "pop r28\n"
        : : "x"(x), "z"(y), "r"(result)
        : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
          "r24", "r25"
    );
#endif // CURVE25519_ASM_AVR
    // Reduce the result using the quick trial subtraction method.
    reduceQuick(result);
}
/**
 * \brief Subtracts two values and then reduces the result modulo 2^255 - 19.
 *
 * \param result The result, which must be NUM_LIMBS_256BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_256BIT
 * limbs in size and less than 2^255 - 19.
 * \param y The second value to multiply, which must be NUM_LIMBS_256BIT
 * limbs in size and less than 2^255 - 19.
 */
void Curve25519::sub(limb_t *result, const limb_t *x, const limb_t *y)
{
#if !defined(CURVE25519_ASM_AVR)
    dlimb_t borrow;
    uint8_t posn;
    limb_t *rr = result;
    // Subtract y from x to generate the intermediate result.
    borrow = 0;
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
        *rr++ = (limb_t)borrow;
    }
    // If we had a borrow, then the result has gone negative and we
    // have to add 2^255 - 19 to the result to make it positive again.
    // The top bits of "borrow" will be all 1's if there is a borrow
    // or it will be all 0's if there was no borrow.  Easiest is to
    // conditionally subtract 19 and then mask off the high bit.
    rr = result;
    borrow = (borrow >> LIMB_BITS) & 19U;
    borrow = ((dlimb_t)(*rr)) - borrow;
    *rr++ = (limb_t)borrow;
    for (posn = 1; posn < NUM_LIMBS_256BIT; ++posn) {
        borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
        *rr++ = (limb_t)borrow;
    }
    *(--rr) &= ((((limb_t)1) << (LIMB_BITS - 1)) - 1);
#else // CURVE25519_ASM_AVR
    __asm__ __volatile__ (
        // Save Y and copy the "result" pointer into it.
        "push r28\n"
        "push r29\n"
        "mov r28,%A2\n"
        "mov r29,%B2\n"
        // Unroll the sub loop to operate on 4 bytes at a time (8 iterations).
        "ldi r24,8\n"               // Loop counter.
        "clr r25\n"                 // borrow = 0
        "1:\n"
        "ld r16,X+\n"               // r16:r19 = *x++
        "ld r17,X+\n"
        "ld r18,X+\n"
        "ld r19,X+\n"
        "ld r20,Z+\n"               // r20:r23 = *y++
        "ld r21,Z+\n"
        "ld r22,Z+\n"
        "ld r23,Z+\n"
        "sub r16,r25\n"             // r16:r19:borrow -= borrow
        "sbc r17,__zero_reg__\n"
        "sbc r18,__zero_reg__\n"
        "sbc r19,__zero_reg__\n"
        "mov r25,__zero_reg__\n"
        "sbc r25,__zero_reg__\n"
        "sub r16,r20\n"             // r16:r19:borrow -= r20:r23
        "sbc r17,r21\n"
        "sbc r18,r22\n"
        "sbc r19,r23\n"
        "sbc r25,__zero_reg__\n"
        "st Y+,r16\n"               // *rr++ = r16:r23
        "st Y+,r17\n"
        "st Y+,r18\n"
        "st Y+,r19\n"
        "andi r25,1\n"              // Only need the bottom bit of the borrow
        "dec r24\n"
        "brne 1b\n"
        // If there was a borrow, then we need to add 2^255 - 19 back.
        // We conditionally subtract 19 and then mask off the high bit.
        "neg r25\n"                 // borrow = mask(borrow) & 19
        "andi r25,19\n"
        "sbiw r28,32\n"             // Point Y back to the start of "result"
        "ldi r24,8\n"
        "2:\n"
        "ld r16,Y\n"                // r16:r19 = *rr
        "ldd r17,Y+1\n"
        "ldd r18,Y+2\n"
        "ldd r19,Y+3\n"
        "sub r16,r25\n"
        "sbc r17,__zero_reg__\n"    // r16:r19:borrow -= borrow
        "sbc r18,__zero_reg__\n"
        "sbc r19,__zero_reg__\n"
        "mov r25,__zero_reg__\n"
        "sbc r25,__zero_reg__\n"
        "andi r25,1\n"
        "st Y+,r16\n"               // *r++ = r16:r19
        "st Y+,r17\n"
        "st Y+,r18\n"
        "st Y+,r19\n"
        "dec r24\n"
        "brne 2b\n"
        "andi r19,0x7F\n"           // Mask off the high bit in the last byte
        "sbiw r28,1\n"
        "st Y,r19\n"
        // Restore Y.
        "pop r29\n"
        "pop r28\n"
        : : "x"(x), "z"(y), "r"(result)
        : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
          "r24", "r25"
    );
#endif // CURVE25519_ASM_AVR
}
/**
 * \brief Conditionally swaps two values if a selection value is non-zero.
 *
 * \param select Non-zero to swap \a x and \a y, zero to leave them unchanged.
 * \param x The first value to conditionally swap.
 * \param y The second value to conditionally swap.
 *
 * The swap is performed in a way that it should take the same amount of
 * time irrespective of the value of \a select.
 *
 * \sa cmove()
 */
void Curve25519::cswap(limb_t select, limb_t *x, limb_t *y)
{
#if !defined(CURVE25519_ASM_AVR)
    uint8_t posn;
    limb_t dummy;
    limb_t sel;
    // Turn "select" into an all-zeroes or all-ones mask.  We don't care
    // which bit or bits is set in the original "select" value.
    sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
    --sel;
    // Swap the two values based on "select".  Algorithm from:
    // http://tools.ietf.org/html/rfc7748
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        dummy = sel & (x[posn] ^ y[posn]);
        x[posn] ^= dummy;
        y[posn] ^= dummy;
    }
#else // CURVE25519_ASM_AVR
    __asm__ __volatile__ (
        // Combine all bytes from "select" into one and then turn
        // that byte into the "sel" mask in r24.
        "clr r24\n"
#if BIGNUMBER_LIMB_8BIT
        "sub r24,%2\n"
#elif BIGNUMBER_LIMB_16BIT
        "or %A2,%B2\n"
        "sub r24,%A2\n"
#elif BIGNUMBER_LIMB_32BIT
        "or %A2,%B2\n"
        "or %A2,%C2\n"
        "or %A2,%D2\n"
        "sub r24,%A2\n"
#endif
        "mov r24,__zero_reg__\n"
        "sbc r24,r24\n"
        // Perform the conditional swap 4 bytes at a time.
        "ldi r25,8\n"
        "1:\n"
        "ld r16,X+\n"           // r16:r19 = *x
        "ld r17,X+\n"
        "ld r18,X+\n"
        "ld r19,X\n"
        "ld r20,Z\n"            // r20:r23 = *y
        "ldd r21,Z+1\n"
        "ldd r22,Z+2\n"
        "ldd r23,Z+3\n"
        "mov r12,r16\n"         // r12:r15 = (r16:r19 ^ r20:r23) & sel
        "mov r13,r17\n"
        "mov r14,r18\n"
        "mov r15,r19\n"
        "eor r12,r20\n"
        "eor r13,r21\n"
        "eor r14,r22\n"
        "eor r15,r23\n"
        "and r12,r24\n"
        "and r13,r24\n"
        "and r14,r24\n"
        "and r15,r24\n"
        "eor r16,r12\n"         // r16:r19 ^= r12:r15
        "eor r17,r13\n"
        "eor r18,r14\n"
        "eor r19,r15\n"
        "eor r20,r12\n"         // r20:r23 ^= r12:r15
        "eor r21,r13\n"
        "eor r22,r14\n"
        "eor r23,r15\n"
        "st X,r19\n"            // *x++ = r16:r19
        "st -X,r18\n"
        "st -X,r17\n"
        "st -X,r16\n"
        "adiw r26,4\n"
        "st Z+,r20\n"           // *y++ = r20:r23
        "st Z+,r21\n"
        "st Z+,r22\n"
        "st Z+,r23\n"
        "dec r25\n"
        "brne 1b\n"
        : : "x"(x), "z"(y), "r"(select)
        : "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
          "r20", "r21", "r22", "r23", "r24", "r25"
    );
#endif // CURVE25519_ASM_AVR
}
/**
 * \brief Conditionally moves \a y into \a x if a selection value is non-zero.
 *
 * \param select Non-zero to move \a y into \a x, zero to leave \a x unchanged.
 * \param x The destination to move into.
 * \param y The value to conditionally move.
 *
 * The move is performed in a way that it should take the same amount of
 * time irrespective of the value of \a select.
 *
 * \sa cswap()
 */
void Curve25519::cmove(limb_t select, limb_t *x, const limb_t *y)
{
#if !defined(CURVE25519_ASM_AVR)
    uint8_t posn;
    limb_t dummy;
    limb_t sel;
    // Turn "select" into an all-zeroes or all-ones mask.  We don't care
    // which bit or bits is set in the original "select" value.
    sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
    --sel;
    // Move y into x based on "select".  Similar to conditional swap above.
    for (posn = 0; posn < NUM_LIMBS_256BIT; ++posn) {
        dummy = sel & (x[posn] ^ y[posn]);
        x[posn] ^= dummy;
    }
#else // CURVE25519_ASM_AVR
    __asm__ __volatile__ (
        // Combine all bytes from "select" into one and then turn
        // that byte into the "sel" mask in r24.
        "clr r24\n"
#if BIGNUMBER_LIMB_8BIT
        "sub r24,%2\n"
#elif BIGNUMBER_LIMB_16BIT
        "or %A2,%B2\n"
        "sub r24,%A2\n"
#elif BIGNUMBER_LIMB_32BIT
        "or %A2,%B2\n"
        "or %A2,%C2\n"
        "or %A2,%D2\n"
        "sub r24,%A2\n"
#endif
        "mov r24,__zero_reg__\n"
        "sbc r24,r24\n"
        // Perform the conditional move 4 bytes at a time.
        "ldi r25,8\n"
        "1:\n"
        "ld r16,X+\n"           // r16:r19 = *x
        "ld r17,X+\n"
        "ld r18,X+\n"
        "ld r19,X\n"
        "ld r20,Z+\n"           // r20:r23 = *y++
        "ld r21,Z+\n"
        "ld r22,Z+\n"
        "ld r23,Z+\n"
        "eor r20,r16\n"         // r20:r23 = (r16:r19 ^ r20:r23) & sel
        "eor r21,r17\n"
        "eor r22,r18\n"
        "eor r23,r19\n"
        "and r20,r24\n"
        "and r21,r24\n"
        "and r22,r24\n"
        "and r23,r24\n"
        "eor r16,r20\n"         // r16:r19 ^= r20:r23
        "eor r17,r21\n"
        "eor r18,r22\n"
        "eor r19,r23\n"
        "st X,r19\n"            // *x++ = r16:r19
        "st -X,r18\n"
        "st -X,r17\n"
        "st -X,r16\n"
        "adiw r26,4\n"
        "dec r25\n"
        "brne 1b\n"
        : : "x"(x), "z"(y), "r"(select)
        : "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
          "r24", "r25"
    );
#endif // CURVE25519_ASM_AVR
}
/**
 * \brief Raise x to the power of (2^250 - 1).
 *
 * \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
 * \param x The value to raise.
 */
void Curve25519::pow250(limb_t *result, const limb_t *x)
{
    limb_t t1[NUM_LIMBS_256BIT];
    uint8_t i, j;
    // The big-endian hexadecimal expansion of (2^250 - 1) is:
    // 03FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
    //
    // The naive implementation needs to do 2 multiplications per 1 bit and
    // 1 multiplication per 0 bit.  We can improve upon this by creating a
    // pattern 0000000001 ... 0000000001.  If we square and multiply the
    // pattern by itself we can turn the pattern into the partial results
    // 0000000011 ... 0000000011, 0000000111 ... 0000000111, etc.
    // This averages out to about 1.1 multiplications per 1 bit instead of 2.
    // Build a pattern of 250 bits in length of repeated copies of 0000000001.
    #define RECIP_GROUP_SIZE 10
    #define RECIP_GROUP_BITS 250    // Must be a multiple of RECIP_GROUP_SIZE.
    square(t1, x);
    for (j = 0; j < (RECIP_GROUP_SIZE - 1); ++j)
        square(t1, t1);
    mul(result, t1, x);
    for (i = 0; i < ((RECIP_GROUP_BITS / RECIP_GROUP_SIZE) - 2); ++i) {
        for (j = 0; j < RECIP_GROUP_SIZE; ++j)
            square(t1, t1);
        mul(result, result, t1);
    }
    // Multiply bit-shifted versions of the 0000000001 pattern into
    // the result to "fill in" the gaps in the pattern.
    square(t1, result);
    mul(result, result, t1);
    for (j = 0; j < (RECIP_GROUP_SIZE - 2); ++j) {
        square(t1, t1);
        mul(result, result, t1);
    }
    // Clean up and exit.
    clean(t1);
}
/**
 * \brief Computes the reciprocal of a number modulo 2^255 - 19.
 *
 * \param result The result as a array of NUM_LIMBS_256BIT limbs in size.
 * This cannot be the same array as \a x.
 * \param x The number to compute the reciprocal for.
 */
void Curve25519::recip(limb_t *result, const limb_t *x)
{
    // The reciprocal is the same as x ^ (p - 2) where p = 2^255 - 19.
    // The big-endian hexadecimal expansion of (p - 2) is:
    // 7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFEB
    // Start with the 250 upper bits of the expansion of (p - 2).
    pow250(result, x);
    // Deal with the 5 lowest bits of (p - 2), 01011, from highest to lowest.
    square(result, result);
    square(result, result);
    mul(result, result, x);
    square(result, result);
    square(result, result);
    mul(result, result, x);
    square(result, result);
    mul(result, result, x);
}
/**
 * \brief Computes the square root of a number modulo 2^255 - 19.
 *
 * \param result The result as a array of NUM_LIMBS_256BIT limbs in size.
 * This must not overlap with \a x.
 * \param x The number to compute the square root for.
 *
 * For any number \a x, there are two square roots: positive and negative.
 * For example, both 2 and -2 are square roots of 4 because 2 * 2 = -2 * -2.
 * This function will return one or the other.  Callers must determine which
 * square root they are interested in and invert the result as necessary.
 *
 * \note This function is not constant time so it should only be used
 * on publicly-known values.
 */
bool Curve25519::sqrt(limb_t *result, const limb_t *x)
{
    // sqrt(-1) mod (2^255 - 19).
    static limb_t const numSqrtM1[NUM_LIMBS_256BIT] PROGMEM = {
        LIMB_PAIR(0x4A0EA0B0, 0xC4EE1B27), LIMB_PAIR(0xAD2FE478, 0x2F431806),
        LIMB_PAIR(0x3DFBD7A7, 0x2B4D0099), LIMB_PAIR(0x4FC1DF0B, 0x2B832480)
    };
    limb_t y[NUM_LIMBS_256BIT];
    // Algorithm from: http://tools.ietf.org/html/rfc7748
    // Compute a candidate root: result = x^((p + 3) / 8) mod p.
    // (p + 3) / 8 = (2^252 - 2) which is 251 one bits followed by a zero:
    // 0FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE
    pow250(result, x);
    square(result, result);
    mul(result, result, x);
    square(result, result);
    // Did we get the square root immediately?
    square(y, result);
    if (memcmp(x, y, sizeof(y)) == 0) {
        clean(y);
        return true;
    }
    // Multiply the result by sqrt(-1) and check again.
    mul_P(result, result, numSqrtM1);
    square(y, result);
    if (memcmp(x, y, sizeof(y)) == 0) {
        clean(y);
        return true;
    }
    // The number does not have a square root.
    clean(y);
    return false;
}
src/modules/Crypto/Curve25519.h
New file
@@ -0,0 +1,77 @@
/*
 * 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.
 */
#ifndef CRYPTO_CURVE25519_h
#define CRYPTO_CURVE25519_h
#include "BigNumberUtil.h"
class Ed25519;
class Curve25519
{
public:
    static bool eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32]);
    static void dh1(uint8_t k[32], uint8_t f[32]);
    static bool dh2(uint8_t k[32], uint8_t f[32]);
#if defined(TEST_CURVE25519_FIELD_OPS)
public:
#else
private:
#endif
    static uint8_t isWeakPoint(const uint8_t k[32]);
    static void reduce(limb_t *result, limb_t *x, uint8_t size);
    static limb_t reduceQuick(limb_t *x);
    static void mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y);
    static void mul(limb_t *result, const limb_t *x, const limb_t *y);
    static void square(limb_t *result, const limb_t *x)
    {
        mul(result, x, x);
    }
    static void mulA24(limb_t *result, const limb_t *x);
    static void mul_P(limb_t *result, const limb_t *x, const limb_t *y);
    static void add(limb_t *result, const limb_t *x, const limb_t *y);
    static void sub(limb_t *result, const limb_t *x, const limb_t *y);
    static void cswap(limb_t select, limb_t *x, limb_t *y);
    static void cmove(limb_t select, limb_t *x, const limb_t *y);
    static void pow250(limb_t *result, const limb_t *x);
    static void recip(limb_t *result, const limb_t *x);
    static bool sqrt(limb_t *result, const limb_t *x);
    // Constructor and destructor are private - cannot instantiate this class.
    Curve25519() {}
    ~Curve25519() {}
    friend class Ed25519;
};
#endif
src/modules/Crypto/EAX.cpp
New file
@@ -0,0 +1,293 @@
/*
 * 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 "EAX.h"
#include "Crypto.h"
#include <string.h>
/**
 * \class EAXCommon EAX.h <EAX.h>
 * \brief Concrete base class to assist with implementing EAX for
 * 128-bit block ciphers.
 *
 * References: https://en.wikipedia.org/wiki/EAX_mode,
 * http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
 *
 * \sa EAX
 */
/**
 * \brief Constructs a new cipher in EAX mode.
 *
 * This constructor must be followed by a call to setBlockCipher().
 */
EAXCommon::EAXCommon()
{
    state.encPosn = 0;
    state.authMode = 0;
}
EAXCommon::~EAXCommon()
{
    clean(state);
}
size_t EAXCommon::keySize() const
{
    return omac.blockCipher()->keySize();
}
size_t EAXCommon::ivSize() const
{
    // Can use any size but 16 is recommended.
    return 16;
}
size_t EAXCommon::tagSize() const
{
    // Tags can be up to 16 bytes in length.
    return 16;
}
bool EAXCommon::setKey(const uint8_t *key, size_t len)
{
    return omac.blockCipher()->setKey(key, len);
}
bool EAXCommon::setIV(const uint8_t *iv, size_t len)
{
    // Must have at least 1 byte for the IV.
    if (!len)
        return false;
    // Hash the IV to create the initial nonce for CTR mode.  Also creates B.
    omac.initFirst(state.counter);
    omac.update(state.counter, iv, len);
    omac.finalize(state.counter);
    // The tag is initially the nonce value.  Will be XOR'ed with
    // the hash of the authenticated and encrypted data later.
    memcpy(state.tag, state.counter, 16);
    // Start the hashing context for the authenticated data.
    omac.initNext(state.hash, 1);
    state.encPosn = 16;
    state.authMode = 1;
    // The EAX context is ready to go.
    return true;
}
void EAXCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    if (state.authMode)
        closeAuthData();
    encryptCTR(output, input, len);
    omac.update(state.hash, output, len);
}
void EAXCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    if (state.authMode)
        closeAuthData();
    omac.update(state.hash, input, len);
    encryptCTR(output, input, len);
}
void EAXCommon::addAuthData(const void *data, size_t len)
{
    if (state.authMode)
        omac.update(state.hash, (const uint8_t *)data, len);
}
void EAXCommon::computeTag(void *tag, size_t len)
{
    closeTag();
    if (len > 16)
        len = 16;
    memcpy(tag, state.tag, len);
}
bool EAXCommon::checkTag(const void *tag, size_t len)
{
    // Can never match if the expected tag length is too long.
    if (len > 16)
        return false;
    // Compute the final tag and check it.
    closeTag();
    return secure_compare(state.tag, tag, len);
}
void EAXCommon::clear()
{
    clean(state);
}
/**
 * \brief Closes the authenticated data portion of the session and
 * starts encryption or decryption.
 */
void EAXCommon::closeAuthData()
{
    // Finalise the OMAC hash and XOR it with the final tag.
    omac.finalize(state.hash);
    for (uint8_t index = 0; index < 16; ++index)
        state.tag[index] ^= state.hash[index];
    state.authMode = 0;
    // Initialise the hashing context for the ciphertext data.
    omac.initNext(state.hash, 2);
}
/**
 * \brief Encrypts or decrypts a region using the block cipher in CTR mode.
 *
 * \param output The output buffer to write to, which may be the same
 * buffer as \a input.  The \a output buffer must have at least as many
 * bytes as the \a input buffer.
 * \param input The input buffer to read from.
 * \param len The number of bytes to process.
 */
void EAXCommon::encryptCTR(uint8_t *output, const uint8_t *input, size_t len)
{
    while (len > 0) {
        // Do we need to start a new block?
        if (state.encPosn == 16) {
            // Encrypt the counter to create the next keystream block.
            omac.blockCipher()->encryptBlock(state.stream, state.counter);
            state.encPosn = 0;
            // Increment the counter, taking care not to reveal
            // any timing information about the starting value.
            // We iterate through the entire counter region even
            // if we could stop earlier because a byte is non-zero.
            uint16_t temp = 1;
            uint8_t index = 16;
            while (index > 0) {
                --index;
                temp += state.counter[index];
                state.counter[index] = (uint8_t)temp;
                temp >>= 8;
            }
        }
        // Encrypt/decrypt the current input block.
        uint8_t size = 16 - state.encPosn;
        if (size > len)
            size = (uint8_t)len;
        for (uint8_t index = 0; index < size; ++index)
            output[index] = input[index] ^ state.stream[(state.encPosn)++];
        // Move onto the next block.
        len -= size;
        input += size;
        output += size;
    }
}
void EAXCommon::closeTag()
{
    // If we were only authenticating, then close off auth mode.
    if (state.authMode)
        closeAuthData();
    // Finalise the hash over the ciphertext and XOR with the final tag.
    omac.finalize(state.hash);
    for (uint8_t index = 0; index < 16; ++index)
        state.tag[index] ^= state.hash[index];
}
/**
 * \fn void EAXCommon::setBlockCipher(BlockCipher *cipher)
 * \brief Sets the block cipher to use for this EAX object.
 *
 * \param cipher The block cipher to use to implement EAX mode.
 * This object must have a block size of 128 bits (16 bytes).
 */
/**
 * \class EAX EAX.h <EAX.h>
 * \brief Implementation of the EAX authenticated cipher.
 *
 * EAX mode converts a block cipher into an authenticated cipher
 * that uses the block cipher T to encrypt and authenticate.
 *
 * The size of the key is determined by the underlying block cipher T.
 * The IV is recommended to be 128 bits (16 bytes) in length, but other
 * lengths are supported as well.  The default tagSize() is 128 bits
 * (16 bytes) but the EAX specification does allow smaller tag sizes.
 *
 * The template parameter T must be a concrete subclass of BlockCipher
 * indicating the specific block cipher to use.  The block cipher must
 * have a block size of 128 bits.  For example, the following creates a
 * EAX object using AES256 as the underlying cipher and then uses it
 * to encrypt and authenticate a \c plaintext block:
 *
 * \code
 * EAX<AES256> eax;
 * eax.setKey(key, sizeof(key));
 * eax.setIV(iv, sizeof(iv));
 * eax.addAuthData(adata, sizeof(adata));
 * eax.encrypt(ciphertext, plaintext, sizeof(plaintext));
 * eax.computeTag(tag, sizeof(tag));
 * \endcode
 *
 * The decryption process is almost identical to convert a \c ciphertext and
 * \a tag back into plaintext and then check the tag:
 *
 * \code
 * EAX<AES256> eax;
 * eax.setKey(key, sizeof(key));
 * eax.setIV(iv, sizeof(iv));
 * eax.addAuthData(adata, sizeof(adata));
 * eax.decrypt(ciphertext, plaintext, sizeof(plaintext));
 * if (!eax.checkTag(tag, sizeof(tag))) {
 *     // The data was invalid - do not use it.
 *     ...
 * }
 * \endcode
 *
 * The EAX class can also be used to implement message authentication
 * by omitting the plaintext:
 *
 * \code
 * EAX<AES256> eax;
 * eax.setKey(key, sizeof(key));
 * eax.setIV(iv, sizeof(iv));
 * eax.addAuthData(adata1, sizeof(adata1));
 * eax.addAuthData(adata2, sizeof(adata1));
 * ...
 * eax.addAuthData(adataN, sizeof(adataN));
 * eax.computeTag(tag, sizeof(tag));
 * \endcode
 *
 * References: https://en.wikipedia.org/wiki/EAX_mode,
 * http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
 *
 * \sa EAXCommon, GCM
 */
/**
 * \fn EAX::EAX()
 * \brief Constructs a new EAX object for the block cipher T.
 */
src/modules/Crypto/EAX.h
New file
@@ -0,0 +1,85 @@
/*
 * 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.
 */
#ifndef CRYPTO_EAX_h
#define CRYPTO_EAX_h
#include "AuthenticatedCipher.h"
#include "BlockCipher.h"
#include "OMAC.h"
class EAXCommon : public AuthenticatedCipher
{
public:
    virtual ~EAXCommon();
    size_t keySize() const;
    size_t ivSize() const;
    size_t tagSize() const;
    bool setKey(const uint8_t *key, size_t len);
    bool setIV(const uint8_t *iv, size_t len);
    void encrypt(uint8_t *output, const uint8_t *input, size_t len);
    void decrypt(uint8_t *output, const uint8_t *input, size_t len);
    void addAuthData(const void *data, size_t len);
    void computeTag(void *tag, size_t len);
    bool checkTag(const void *tag, size_t len);
    void clear();
protected:
    EAXCommon();
    void setBlockCipher(BlockCipher *cipher)
    {
        omac.setBlockCipher(cipher);
    }
private:
    struct {
        uint8_t counter[16];
        uint8_t stream[16];
        uint8_t tag[16];
        uint8_t hash[16];
        uint8_t encPosn;
        uint8_t authMode;
    } state;
    OMAC omac;
    void closeAuthData();
    void encryptCTR(uint8_t *output, const uint8_t *input, size_t len);
    void closeTag();
};
template <typename T>
class EAX : public EAXCommon
{
public:
    EAX() { setBlockCipher(&cipher); }
private:
    T cipher;
};
#endif
src/modules/Crypto/Ed25519.cpp
New file
@@ -0,0 +1,642 @@
/*
 * 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 "Ed25519.h"
#include "Curve25519.h"
#include "Crypto.h"
#include "RNG.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
 * \class Ed25519 Ed25519.h <Ed25519.h>
 * \brief Digital signatures based on the elliptic curve modulo 2^255 - 19.
 *
 * The first step in creating a digital signature with Ed25519 is to
 * generate a key pair:
 *
 * \code
 * uint8_t privateKey[32];
 * uint8_t publicKey[32];
 *
 * Ed25519::generatePrivateKey(privateKey);
 * Ed25519::derivePublicKey(publicKey, privateKey);
 * \endcode
 *
 * The application can store both the private and public key for later
 * signing operations.  Or it can store just the private key and then
 * derive the public key at the point where signing is to occur.
 *
 * Message signing produces a 64-byte signature as follows:
 *
 * \code
 * uint8_t message[N];
 * uint8_t signature[64];
 *
 * Ed25519::sign(signature, privateKey, publicKey, message, N);
 * \endcode
 *
 * And then to verify the signature:
 *
 * \code
 * if (!Ed25519::verify(signature, publicKey, message, N)) {
 *     // The signature is invalid.
 *     ...
 * }
 * \endcode
 *
 * \note The public functions in this class need a substantial amount of
 * stack space to store intermediate results while the curve function is
 * being evaluated.  About 1.5k of free stack space is recommended for safety.
 *
 * References: https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05
 *
 * \sa Curve25519
 */
/** @cond */
// 37095705934669439343138083508754565189542113879843219016388785533085940283555
static limb_t const numD[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0x135978A3, 0x75EB4DCA), LIMB_PAIR(0x4141D8AB, 0x00700A4D),
    LIMB_PAIR(0x7779E898, 0x8CC74079), LIMB_PAIR(0x2B6FFE73, 0x52036CEE)
};
// d * 2
static limb_t const numDx2[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0x26B2F159, 0xEBD69B94), LIMB_PAIR(0x8283B156, 0x00E0149A),
    LIMB_PAIR(0xEEF3D130, 0x198E80F2), LIMB_PAIR(0x56DFFCE7, 0x2406D9DC)
};
// Extended homogenous co-ordinates for the base point.
static limb_t const numBx[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0x8F25D51A, 0xC9562D60), LIMB_PAIR(0x9525A7B2, 0x692CC760),
    LIMB_PAIR(0xFDD6DC5C, 0xC0A4E231), LIMB_PAIR(0xCD6E53FE, 0x216936D3)
};
static limb_t const numBy[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0x66666658, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666),
    LIMB_PAIR(0x66666666, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666)
};
static limb_t const numBz[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0x00000001, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000),
    LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000)
};
static limb_t const numBt[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0xA5B7DDA3, 0x6DDE8AB3), LIMB_PAIR(0x775152F5, 0x20F09F80),
    LIMB_PAIR(0x64ABE37D, 0x66EA4E8E), LIMB_PAIR(0xD78B7665, 0x67875F0F)
};
// 2^252 + 27742317777372353535851937790883648493
static limb_t const numQ[NUM_LIMBS_256BIT] PROGMEM = {
    LIMB_PAIR(0x5CF5D3ED, 0x5812631A), LIMB_PAIR(0xA2F79CD6, 0x14DEF9DE),
    LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x10000000)
};
/** @endcond */
/**
 * \brief Signs a message using a specific Ed25519 private key.
 *
 * \param signature The signature value.
 * \param privateKey The private key to use to sign the message.
 * \param publicKey The public key corresponding to \a privateKey.
 * \param message Points to the message to be signed.
 * \param len The length of the \a message to be signed.
 *
 * \sa verify(), derivePublicKey()
 */
void Ed25519::sign(uint8_t signature[64], const uint8_t privateKey[32],
                   const uint8_t publicKey[32], const void *message, size_t len)
{
    SHA512 hash;
    uint8_t *buf = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
    limb_t a[NUM_LIMBS_256BIT];
    limb_t r[NUM_LIMBS_256BIT];
    limb_t k[NUM_LIMBS_256BIT];
    limb_t t[NUM_LIMBS_512BIT + 1];
    Point rB;
    // Derive the secret scalar a and the message prefix from the private key.
    deriveKeys(&hash, a, privateKey);
    // Hash the prefix and the message to derive r.
    hash.reset();
    hash.update(buf + 32, 32);
    hash.update(message, len);
    hash.finalize(buf, 0);
    reduceQFromBuffer(r, buf, t);
    // Encode rB into the first half of the signature buffer as R.
    mul(rB, r);
    encodePoint(signature, rB);
    // Hash R, A, and the message to get k.
    hash.reset();
    hash.update(signature, 32); // R
    hash.update(publicKey, 32); // A
    hash.update(message, len);
    hash.finalize(buf, 0);
    reduceQFromBuffer(k, buf, t);
    // Compute s = (r + k * a) mod q.
    Curve25519::mulNoReduce(t, k, a);
    t[NUM_LIMBS_512BIT] = 0;
    reduceQ(t, t);
    BigNumberUtil::add(t, t, r, NUM_LIMBS_256BIT);
    BigNumberUtil::reduceQuick_P(t, t, numQ, NUM_LIMBS_256BIT);
    BigNumberUtil::packLE(signature + 32, 32, t, NUM_LIMBS_256BIT);
    // Clean up.
    clean(a);
    clean(r);
    clean(k);
    clean(t);
    clean(rB);
}
/**
 * \brief Verifies a signature using a specific Ed25519 public key.
 *
 * \param signature The signature value to be verified.
 * \param publicKey The public key to use to verify the signature.
 * \param message The message whose signature is to be verified.
 * \param len The length of the \a message to be verified.
 *
 * \return Returns true if the \a signature is valid for \a message;
 * or false if the \a signature is not valid.
 *
 * \sa sign()
 */
bool Ed25519::verify(const uint8_t signature[64], const uint8_t publicKey[32],
                     const void *message, size_t len)
{
    SHA512 hash;
    Point A;
    Point R;
    Point sB;
    Point kA;
    uint8_t *k = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
    bool result = false;
    // Decode the public key and the R component of the signature.
    if (decodePoint(A, publicKey) && decodePoint(R, signature)) {
        // Reconstruct the k value from the signing step.
        hash.reset();
        hash.update(signature, 32);
        hash.update(publicKey, 32);
        hash.update(message, len);
        hash.finalize(k, 0);
        // Calculate s * B.  The s value is stored temporarily in kA.t.
        BigNumberUtil::unpackLE(kA.t, NUM_LIMBS_256BIT, signature + 32, 32);
        mul(sB, kA.t, false);
        // Calculate R + k * A.  We don't need sB.t in equal() below,
        // so we reuse that as a temporary buffer when reducing k.
        reduceQFromBuffer(sB.t, k, kA.x);
        mul(kA, sB.t, A, false);
        add(R, kA);
        // Compare s * B and R + k * A for equality.
        result = equal(sB, R);
    }
    // Clean up and exit.
    clean(A);
    clean(R);
    clean(sB);
    clean(kA);
    return result;
}
/**
 * \brief Generates a private key for Ed25519 signing operations.
 *
 * \param privateKey The resulting private key.
 *
 * The private key is generated with \link RNGClass::rand() RNG.rand()\endlink.
 * It is the caller's responsibility to ensure that the global random number
 * pool has sufficient entropy to generate the 32 bytes of the key safely
 * before calling this function.
 *
 * \sa derivePublicKey()
 */
void Ed25519::generatePrivateKey(uint8_t privateKey[32])
{
    RNG.rand(privateKey, 32);
}
/**
 * \brief Derives the public key from a private key.
 *
 * \param publicKey The public key.
 * \param privateKey The private key.
 *
 * \sa generatePrivateKey()
 */
void Ed25519::derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32])
{
    SHA512 hash;
    limb_t a[NUM_LIMBS_256BIT];
    Point ptA;
    // Derive the secret scalar a from the private key.
    deriveKeys(&hash, a, privateKey);
    // Compute the point A = aB and encode it.
    mul(ptA, a);
    encodePoint(publicKey, ptA);
    // Clean up and exit.
    clean(a);
    clean(ptA);
}
/**
 * \brief Reduces a number modulo q that was specified in a 512 bit buffer.
 *
 * \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
 * \param buf The buffer containing the value to reduce in little-endian order.
 * \param temp A temporary buffer of at least NUM_LIMBS_512BIT + 1 in size.
 *
 * \sa reduceQ()
 */
void Ed25519::reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp)
{
    BigNumberUtil::unpackLE(temp, NUM_LIMBS_512BIT, buf, 64);
    temp[NUM_LIMBS_512BIT] = 0;
    reduceQ(result, temp);
}
/**
 * \brief Reduces a number modulo q.
 *
 * \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
 * \param r The value to reduce, which must be NUM_LIMBS_512BIT + 1
 * limbs in size.
 *
 * The \a r array will be modified by this function as a side effect of
 * the division.  It is allowed for \a result to be the same as \a r.
 *
 * \sa reduceQFromBuffer()
 */
void Ed25519::reduceQ(limb_t *result, limb_t *r)
{
    // Algorithm from: http://en.wikipedia.org/wiki/Barrett_reduction
    //
    // We assume that r is less than or equal to (q - 1)^2.
    //
    // We want to compute result = r mod q.  Find the smallest k such
    // that 2^k > q.  In our case, k = 253.  Then set m = floor(4^k / q)
    // and let r = r - q * floor(m * r / 4^k).  This will be the result
    // or it will be at most one subtraction of q away from the result.
    //
    // Note: 4^k = 4^253 = 2^506 = 2^512/2^6.  We can more easily compute
    // the result we want if we set m = floor(4^k * 2^6 / q) instead and
    // then r = r - q * floor(m * r / 2^512).  Because the slight extra
    // precision in m, r is at most two subtractions of q away from the
    // final result.
    static limb_t const numM[NUM_LIMBS_256BIT + 1] PROGMEM = {
        LIMB_PAIR(0x0A2C131B, 0xED9CE5A3), LIMB_PAIR(0x086329A7, 0x2106215D),
        LIMB_PAIR(0xFFFFFFEB, 0xFFFFFFFF), LIMB_PAIR(0xFFFFFFFF, 0xFFFFFFFF),
        0x0F
    };
    limb_t temp[NUM_LIMBS_512BIT + NUM_LIMBS_256BIT + 1];
    // Multiply r by m.
    BigNumberUtil::mul_P(temp, r, NUM_LIMBS_512BIT, numM, NUM_LIMBS_256BIT + 1);
    // Multiply (m * r) / 2^512 by q and subtract it from r.
    // We can ignore the high words of the subtraction result
    // because they will all turn into zero after the subtraction.
    BigNumberUtil::mul_P(temp, temp + NUM_LIMBS_512BIT, NUM_LIMBS_256BIT + 1,
                         numQ, NUM_LIMBS_256BIT);
    BigNumberUtil::sub(r, r, temp, NUM_LIMBS_256BIT);
    // Perform two subtractions of q from the result to reduce it.
    BigNumberUtil::reduceQuick_P(result, r, numQ, NUM_LIMBS_256BIT);
    BigNumberUtil::reduceQuick_P(result, result, numQ, NUM_LIMBS_256BIT);
    // Clean up and exit.
    clean(temp);
}
/**
 * \brief Multiplies a value by a curve point.
 *
 * \param result The result of the multiplication.
 * \param s The value, which must be NUM_LIMBS_256BIT limbs in size.
 * \param p The curve point, which will be modified by this function.
 * \param constTime Set to true if the evaluation must be constant-time
 * because \a s is a secret value.
 */
void Ed25519::mul(Point &result, const limb_t *s, Point &p, bool constTime)
{
    Point q;
    limb_t A[NUM_LIMBS_256BIT];
    limb_t B[NUM_LIMBS_256BIT];
    limb_t C[NUM_LIMBS_256BIT];
    limb_t D[NUM_LIMBS_256BIT];
    limb_t mask, select;
    uint8_t sposn, t;
    // Initialize the result to (0, 1, 1, 0).
    memset(&result, 0, sizeof(Point));
    result.y[0] = 1;
    result.z[0] = 1;
    // Iterate over the 255 bits of "s" to calculate "s * p".
    mask = 1;
    sposn = 0;
    for (t = 255; t > 0; --t) {
        // Add p to the result to produce q.  The specification refers
        // to temporary variables A to H.  We can dispense with E to H
        // by using B, D, q.z, and q.t to hold those values temporarily.
        select = s[sposn] & mask;
        if (constTime || select) {
            Curve25519::sub(A, result.y, result.x);
            Curve25519::sub(C, p.y, p.x);
            Curve25519::mul(A, A, C);
            Curve25519::add(B, result.y, result.x);
            Curve25519::add(C, p.y, p.x);
            Curve25519::mul(B, B, C);
            Curve25519::mul(C, result.t, p.t);
            Curve25519::mul_P(C, C, numDx2);
            Curve25519::mul(D, result.z, p.z);
            Curve25519::add(D, D, D);
            Curve25519::sub(q.t, B, A);             // E = B - A
            Curve25519::sub(q.z, D, C);             // F = D - C
            Curve25519::add(D, D, C);               // G = D + C
            Curve25519::add(B, B, A);               // H = B + A
            if (constTime) {
                // Put the intermediate value into q.
                Curve25519::mul(q.x, q.t, q.z);         // q.x = E * F
                Curve25519::mul(q.y, D, B);             // q.y = G * H
                Curve25519::mul(q.z, q.z, D);           // q.z = F * G
                Curve25519::mul(q.t, q.t, B);           // q.t = E * H
                // Copy q into the result if the current bit of s is 1.
                Curve25519::cmove(select, result.x, q.x);
                Curve25519::cmove(select, result.y, q.y);
                Curve25519::cmove(select, result.z, q.z);
                Curve25519::cmove(select, result.t, q.t);
            } else {
                // Put the intermediate value directly into the result.
                Curve25519::mul(result.x, q.t, q.z);     // q.x = E * F
                Curve25519::mul(result.y, D, B);         // q.y = G * H
                Curve25519::mul(result.z, q.z, D);       // q.z = F * G
                Curve25519::mul(result.t, q.t, B);       // q.t = E * H
            }
        }
        // Double p for the next iteration.
        Curve25519::sub(A, p.y, p.x);
        Curve25519::square(A, A);
        Curve25519::add(B, p.y, p.x);
        Curve25519::square(B, B);
        Curve25519::square(C, p.t);
        Curve25519::mul_P(C, C, numDx2);
        Curve25519::square(D, p.z);
        Curve25519::add(D, D, D);
        Curve25519::sub(p.t, B, A);             // E = B - A
        Curve25519::sub(p.z, D, C);             // F = D - C
        Curve25519::add(D, D, C);               // G = D + C
        Curve25519::add(B, B, A);               // H = B + A
        Curve25519::mul(p.x, p.t, p.z);         // p.x = E * F
        Curve25519::mul(p.y, D, B);             // p.y = G * H
        Curve25519::mul(p.z, p.z, D);           // p.z = F * G
        Curve25519::mul(p.t, p.t, B);           // p.t = E * H
        // Move onto the next bit of s from lowest to highest.
        if (mask != (((limb_t)1) << (LIMB_BITS - 1))) {
            mask <<= 1;
        } else {
            ++sposn;
            mask = 1;
        }
    }
    // Clean up.
    clean(q);
    clean(A);
    clean(B);
    clean(C);
    clean(D);
}
/**
 * \brief Multiplies a value by the base point of the curve.
 *
 * \param result The result of the multiplication.
 * \param s The value, which must be NUM_LIMBS_256BIT limbs in size.
 * \param constTime Set to true if the evaluation must be constant-time
 * because \a s is a secret values.
 */
void Ed25519::mul(Point &result, const limb_t *s, bool constTime)
{
    Point P;
    memcpy_P(P.x, numBx, sizeof(P.x));
    memcpy_P(P.y, numBy, sizeof(P.y));
    memcpy_P(P.z, numBz, sizeof(P.z));
    memcpy_P(P.t, numBt, sizeof(P.t));
    mul(result, s, P, constTime);
    clean(P);
}
/**
 * \brief Adds two curve points.
 *
 * \param p The first point and the result.
 * \param q The second point.
 */
void Ed25519::add(Point &p, const Point &q)
{
    limb_t A[NUM_LIMBS_256BIT];
    limb_t B[NUM_LIMBS_256BIT];
    limb_t C[NUM_LIMBS_256BIT];
    limb_t D[NUM_LIMBS_256BIT];
    Curve25519::sub(A, p.y, p.x);
    Curve25519::sub(C, q.y, q.x);
    Curve25519::mul(A, A, C);
    Curve25519::add(B, p.y, p.x);
    Curve25519::add(C, q.y, q.x);
    Curve25519::mul(B, B, C);
    Curve25519::mul(C, p.t, q.t);
    Curve25519::mul_P(C, C, numDx2);
    Curve25519::mul(D, p.z, q.z);
    Curve25519::add(D, D, D);
    Curve25519::sub(p.t, B, A);             // E = B - A
    Curve25519::sub(p.z, D, C);             // F = D - C
    Curve25519::add(D, D, C);               // G = D + C
    Curve25519::add(B, B, A);               // H = B + A
    Curve25519::mul(p.x, p.t, p.z);         // p.x = E * F
    Curve25519::mul(p.y, D, B);             // p.y = G * H
    Curve25519::mul(p.z, p.z, D);           // p.z = F * G
    Curve25519::mul(p.t, p.t, B);           // p.t = E * H
    clean(A);
    clean(B);
    clean(C);
    clean(D);
}
/**
 * \brief Determine if two curve points are equal.
 *
 * \param p The first curve point.
 * \param q The second curve point.
 *
 * \return Returns true if \a p and \a q are equal; false otherwise.
 */
bool Ed25519::equal(const Point &p, const Point &q)
{
    limb_t a[NUM_LIMBS_256BIT];
    limb_t b[NUM_LIMBS_256BIT];
    bool result = true;
    Curve25519::mul(a, p.x, q.z);
    Curve25519::mul(b, q.x, p.z);
    result &= secure_compare(a, b, sizeof(a));
    Curve25519::mul(a, p.y, q.z);
    Curve25519::mul(b, q.y, p.z);
    result &= secure_compare(a, b, sizeof(a));
    clean(a);
    clean(b);
    return result;
}
/**
 * \brief Encodes a curve point into a 32-byte buffer.
 *
 * \param buf The buffer to encode into.
 * \param point The curve point to encode.  This value will be modified
 * the function and effectively destroyed.
 *
 * \sa decodePoint()
 */
void Ed25519::encodePoint(uint8_t *buf, Point &point)
{
    // Convert the homogeneous coordinates into plain (x, y) coordinates:
    //      zinv = z^(-1) mod p
    //      x = x * zinv  mod p
    //      y = y * zinv  mod p
    // We don't need the t coordinate, so use that to store zinv temporarily.
    Curve25519::recip(point.t, point.z);
    Curve25519::mul(point.x, point.x, point.t);
    Curve25519::mul(point.y, point.y, point.t);
    // Copy the lowest bit of x to the highest bit of y.
    point.y[NUM_LIMBS_256BIT - 1] |= (point.x[0] << (LIMB_BITS - 1));
    // Convert y into little-endian in the return buffer.
    BigNumberUtil::packLE(buf, 32, point.y, NUM_LIMBS_256BIT);
}
/**
 * \brief Decodes a curve point from a 32-byte buffer.
 *
 * \param point The curve point that was decoded from the buffer.
 * \param buf The buffer to decode.
 *
 * \return Returns true if the point was decoded or false if the contents
 * of the buffer do not correspond to a legitimate curve point.
 *
 * \note This function is not constant time so it should only be used
 * on publicly-known values.
 */
bool Ed25519::decodePoint(Point &point, const uint8_t *buf)
{
    limb_t temp[NUM_LIMBS_256BIT];
    // Convert the input buffer from little-endian into the limbs of y.
    BigNumberUtil::unpackLE(point.y, NUM_LIMBS_256BIT, buf, 32);
    // The high bit of y is the sign bit for x.
    limb_t sign = point.y[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1);
    point.y[NUM_LIMBS_256BIT - 1] &= ~(((limb_t)1) << (LIMB_BITS - 1));
    // Set z to 1.
    memcpy_P(point.z, numBz, sizeof(point.z));
    // Compute t = (y * y - 1) * modinv(d * y * y + 1).
    Curve25519::square(point.t, point.y);
    Curve25519::sub(point.x, point.t, point.z);
    Curve25519::mul_P(point.t, point.t, numD);
    Curve25519::add(point.t, point.t, point.z);
    Curve25519::recip(temp, point.t);
    Curve25519::mul(point.t, point.x, temp);
    clean(temp);
    // Check for t = 0.
    limb_t check = point.t[0];
    for (uint8_t posn = 1; posn < NUM_LIMBS_256BIT; ++posn)
        check |= point.t[posn];
    if (!check) {
        // If the sign bit is set, then decoding has failed.
        // Otherwise x is zero and we're done.
        if (sign)
            return false;
        memset(point.x, 0, sizeof(point.x));
        return true;
    }
    // Recover x by taking the sqrt of t and flipping the sign if necessary.
    if (!Curve25519::sqrt(point.x, point.t))
        return false;
    if (sign != (point.x[0] & ((limb_t)1))) {
        // The signs are different so we want the other square root.
        memset(point.t, 0, sizeof(point.t));
        Curve25519::sub(point.x, point.t, point.x);
    }
    // Finally, t = x * y.
    Curve25519::mul(point.t, point.x, point.y);
    return true;
}
/**
 * \brief Derive key material from a 32-byte private key.
 *
 * \param hash SHA512 hash object from the caller for use in this function.
 * The 64-byte output buffer within this hash object will contain the
 * hash prefix on exit.
 * \param a The secret scalar derived from \a privateKey.  This must be
 * NUM_LIMBS_256BIT limbs in size.
 * \param privateKey The 32-byte private key to derive all other values from.
 */
void Ed25519::deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32])
{
    // Hash the private key to get the "a" scalar and the message prefix.
    uint8_t *buf = (uint8_t *)(hash->state.w); // Reuse hash buffer to save memory.
    hash->reset();
    hash->update(privateKey, 32);
    hash->finalize(buf, 0);
    buf[0]  &= 0xF8;
    buf[31] &= 0x7F;
    buf[31] |= 0x40;
    // Unpack the first half of the hash value into "a".
    BigNumberUtil::unpackLE(a, NUM_LIMBS_256BIT, buf, 32);
}
src/modules/Crypto/Ed25519.h
New file
@@ -0,0 +1,71 @@
/*
 * 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.
 */
#ifndef CRYPTO_ED25519_h
#define CRYPTO_ED25519_h
#include "BigNumberUtil.h"
#include "SHA512.h"
class Ed25519
{
public:
    static void sign(uint8_t signature[64], const uint8_t privateKey[32],
                     const uint8_t publicKey[32], const void *message,
                     size_t len);
    static bool verify(const uint8_t signature[64], const uint8_t publicKey[32],
                       const void *message, size_t len);
    static void generatePrivateKey(uint8_t privateKey[32]);
    static void derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32]);
private:
    // Constructor and destructor are private - cannot instantiate this class.
    Ed25519();
    ~Ed25519();
    // Curve point represented in extended homogeneous coordinates.
    struct Point
    {
        limb_t x[32 / sizeof(limb_t)];
        limb_t y[32 / sizeof(limb_t)];
        limb_t z[32 / sizeof(limb_t)];
        limb_t t[32 / sizeof(limb_t)];
    };
    static void reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp);
    static void reduceQ(limb_t *result, limb_t *r);
    static void mul(Point &result, const limb_t *s, Point &p, bool constTime = true);
    static void mul(Point &result, const limb_t *s, bool constTime = true);
    static void add(Point &p, const Point &q);
    static bool equal(const Point &p, const Point &q);
    static void encodePoint(uint8_t *buf, Point &point);
    static bool decodePoint(Point &point, const uint8_t *buf);
    static void deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32]);
};
#endif
src/modules/Crypto/GCM.cpp
New file
@@ -0,0 +1,335 @@
/*
 * 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 "GCM.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include <string.h>
/**
 * \class GCMCommon GCM.h <GCM.h>
 * \brief Concrete base class to assist with implementing GCM for
 * 128-bit block ciphers.
 *
 * References: <a href="http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">NIST SP 800-38D</a>,
 * http://en.wikipedia.org/wiki/Galois/Counter_Mode
 *
 * \sa GCM
 */
/**
 * \brief Constructs a new cipher in GCM mode.
 *
 * This constructor must be followed by a call to setBlockCipher().
 */
GCMCommon::GCMCommon()
    : blockCipher(0)
{
    state.authSize = 0;
    state.dataSize = 0;
    state.dataStarted = false;
    state.posn = 16;
}
/**
 * \brief Destroys this cipher object after clearing sensitive information.
 */
GCMCommon::~GCMCommon()
{
    clean(state);
}
size_t GCMCommon::keySize() const
{
    return blockCipher->keySize();
}
size_t GCMCommon::ivSize() const
{
    // The GCM specification recommends an IV size of 96 bits.
    return 12;
}
size_t GCMCommon::tagSize() const
{
    return 16;
}
bool GCMCommon::setKey(const uint8_t *key, size_t len)
{
    // Set the encryption key for the block cipher.
    return blockCipher->setKey(key, len);
}
bool GCMCommon::setIV(const uint8_t *iv, size_t len)
{
    // Format the counter block from the IV.
    if (len == 12) {
        // IV's of exactly 96 bits are used directly as the counter block.
        memcpy(state.counter, iv, 12);
        state.counter[12] = 0;
        state.counter[13] = 0;
        state.counter[14] = 0;
        state.counter[15] = 1;
    } else {
        // IV's of other sizes are hashed to produce the counter block.
        memset(state.nonce, 0, 16);
        blockCipher->encryptBlock(state.nonce, state.nonce);
        ghash.reset(state.nonce);
        ghash.update(iv, len);
        ghash.pad();
        uint64_t sizes[2] = {0, htobe64(((uint64_t)len) * 8)};
        ghash.update(sizes, sizeof(sizes));
        clean(sizes);
        ghash.finalize(state.counter, 16);
    }
    // Reset the GCM object ready to process auth or payload data.
    state.authSize = 0;
    state.dataSize = 0;
    state.dataStarted = false;
    state.posn = 16;
    // Construct the hashing key by encrypting a zero block.
    memset(state.nonce, 0, 16);
    blockCipher->encryptBlock(state.nonce, state.nonce);
    ghash.reset(state.nonce);
    // Replace the hash key in "nonce" with the encrypted counter.
    // This value will be XOR'ed with the final authentication hash
    // value in computeTag().
    blockCipher->encryptBlock(state.nonce, state.counter);
    return true;
}
/**
 * \brief Increments the least significant 32 bits of the counter block.
 *
 * \param counter The counter block to increment.
 */
static inline void increment(uint8_t counter[16])
{
    uint16_t carry = 1;
    carry += counter[15];
    counter[15] = (uint8_t)carry;
    carry = (carry >> 8) + counter[14];
    counter[14] = (uint8_t)carry;
    carry = (carry >> 8) + counter[13];
    counter[13] = (uint8_t)carry;
    carry = (carry >> 8) + counter[12];
    counter[12] = (uint8_t)carry;
}
void GCMCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    // Finalize the authenticated data if necessary.
    if (!state.dataStarted) {
        ghash.pad();
        state.dataStarted = true;
    }
    // Encrypt the plaintext using the block cipher in counter mode.
    uint8_t *out = output;
    size_t size = len;
    while (size > 0) {
        // Create a new keystream block if necessary.
        if (state.posn >= 16) {
            increment(state.counter);
            blockCipher->encryptBlock(state.stream, state.counter);
            state.posn = 0;
        }
        // Encrypt as many bytes as we can using the keystream block.
        uint8_t temp = 16 - state.posn;
        if (temp > size)
            temp = size;
        uint8_t *stream = state.stream + state.posn;
        state.posn += temp;
        size -= temp;
        while (temp > 0) {
            *out++ = *input++ ^ *stream++;
            --temp;
        }
    }
    // Feed the ciphertext into the hash.
    ghash.update(output, len);
    state.dataSize += len;
}
void GCMCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    // Finalize the authenticated data if necessary.
    if (!state.dataStarted) {
        ghash.pad();
        state.dataStarted = true;
    }
    // Feed the ciphertext into the hash before we decrypt it.
    ghash.update(input, len);
    state.dataSize += len;
    // Decrypt the plaintext using the block cipher in counter mode.
    while (len > 0) {
        // Create a new keystream block if necessary.
        if (state.posn >= 16) {
            increment(state.counter);
            blockCipher->encryptBlock(state.stream, state.counter);
            state.posn = 0;
        }
        // Decrypt as many bytes as we can using the keystream block.
        uint8_t temp = 16 - state.posn;
        if (temp > len)
            temp = len;
        uint8_t *stream = state.stream + state.posn;
        state.posn += temp;
        len -= temp;
        while (temp > 0) {
            *output++ = *input++ ^ *stream++;
            --temp;
        }
    }
}
void GCMCommon::addAuthData(const void *data, size_t len)
{
    if (!state.dataStarted) {
        ghash.update(data, len);
        state.authSize += len;
    }
}
void GCMCommon::computeTag(void *tag, size_t len)
{
    // Pad the hashed data and add the sizes.
    ghash.pad();
    uint64_t sizes[2] = {
        htobe64(state.authSize * 8),
        htobe64(state.dataSize * 8)
    };
    ghash.update(sizes, sizeof(sizes));
    clean(sizes);
    // Get the finalized hash, encrypt it with the nonce, and return the tag.
    ghash.finalize(state.stream, 16);
    for (uint8_t posn = 0; posn < 16; ++posn)
        state.stream[posn] ^= state.nonce[posn];
    if (len > 16)
        len = 16;
    memcpy(tag, state.stream, len);
}
bool GCMCommon::checkTag(const void *tag, size_t len)
{
    // Can never match if the expected tag length is too long.
    if (len > 16)
        return false;
    // Compute the tag and check it.
    computeTag(state.counter, 16);
    return secure_compare(state.counter, tag, len);
}
void GCMCommon::clear()
{
    blockCipher->clear();
    ghash.clear();
    clean(state);
    state.posn = 16;
}
/**
 * \fn void GCMCommon::setBlockCipher(BlockCipher *cipher)
 * \brief Sets the block cipher to use for this GCM object.
 *
 * \param cipher The block cipher to use to implement GCM mode.
 * This object must have a block size of 128 bits (16 bytes).
 */
/**
 * \class GCM GCM.h <GCM.h>
 * \brief Implementation of the Galois Counter Mode (GCM).
 *
 * GCM mode converts a block cipher into an authenticated cipher
 * that uses the block cipher T to encrypt and GHASH to authenticate.
 *
 * The size of the key is determined by the underlying block cipher T.
 * The IV is recommended to be 96 bits (12 bytes) in length, but other
 * lengths are supported as well.  The default tagSize() is 128 bits
 * (16 bytes) but the GCM specification does allow other tag sizes:
 * 32, 64, 96, 104, 112, 120, or 128 bits (4, 8, 12, 13, 14, 15, or 16 bytes).
 *
 * The template parameter T must be a concrete subclass of BlockCipher
 * indicating the specific block cipher to use.  The block cipher must
 * have a block size of 128 bits.  For example, the following creates a
 * GCM object using AES256 as the underlying cipher and then uses it
 * to encrypt and authenticate a \c plaintext block:
 *
 * \code
 * GCM<AES256> gcm;
 * gcm.setKey(key, sizeof(key));
 * gcm.setIV(iv, sizeof(iv));
 * gcm.addAuthData(adata, sizeof(adata));
 * gcm.encrypt(ciphertext, plaintext, sizeof(plaintext));
 * gcm.computeTag(tag, sizeof(tag));
 * \endcode
 *
 * The decryption process is almost identical to convert a \c ciphertext and
 * \a tag back into plaintext and then check the tag:
 *
 * \code
 * GCM<AES256> gcm;
 * gcm.setKey(key, sizeof(key));
 * gcm.setIV(iv, sizeof(iv));
 * gcm.addAuthData(adata, sizeof(adata));
 * gcm.decrypt(ciphertext, plaintext, sizeof(plaintext));
 * if (!gcm.checkTag(tag, sizeof(tag))) {
 *     // The data was invalid - do not use it.
 *     ...
 * }
 * \endcode
 *
 * The GCM class can also be used to implement GMAC message authentication
 * by omitting the plaintext:
 *
 * \code
 * GCM<AES256> gcm;
 * gcm.setKey(key, sizeof(key));
 * gcm.setIV(iv, sizeof(iv));
 * gcm.addAuthData(adata1, sizeof(adata1));
 * gcm.addAuthData(adata2, sizeof(adata1));
 * ...
 * gcm.addAuthData(adataN, sizeof(adataN));
 * gcm.computeTag(tag, sizeof(tag));
 * \endcode
 *
 * References: <a href="http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">NIST SP 800-38D</a>,
 * http://en.wikipedia.org/wiki/Galois/Counter_Mode
 *
 * \sa GCMCommon, GHASH
 */
/**
 * \fn GCM::GCM()
 * \brief Constructs a new GCM object for the block cipher T.
 */
src/modules/Crypto/GCM.h
New file
@@ -0,0 +1,80 @@
/*
 * 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.
 */
#ifndef CRYPTO_GCM_h
#define CRYPTO_GCM_h
#include "AuthenticatedCipher.h"
#include "BlockCipher.h"
#include "GHASH.h"
class GCMCommon : public AuthenticatedCipher
{
public:
    virtual ~GCMCommon();
    size_t keySize() const;
    size_t ivSize() const;
    size_t tagSize() const;
    bool setKey(const uint8_t *key, size_t len);
    bool setIV(const uint8_t *iv, size_t len);
    void encrypt(uint8_t *output, const uint8_t *input, size_t len);
    void decrypt(uint8_t *output, const uint8_t *input, size_t len);
    void addAuthData(const void *data, size_t len);
    void computeTag(void *tag, size_t len);
    bool checkTag(const void *tag, size_t len);
    void clear();
protected:
    GCMCommon();
    void setBlockCipher(BlockCipher *cipher) { blockCipher = cipher; }
private:
    BlockCipher *blockCipher;
    GHASH ghash;
    struct {
        uint8_t counter[16];
        uint8_t stream[16];
        uint8_t nonce[16];
        uint64_t authSize;
        uint64_t dataSize;
        bool dataStarted;
        uint8_t posn;
    } state;
};
template <typename T>
class GCM : public GCMCommon
{
public:
    GCM() { setBlockCipher(&cipher); }
private:
    T cipher;
};
#endif
src/modules/Crypto/GF128.cpp
New file
@@ -0,0 +1,571 @@
/*
 * 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 "GF128.h"
#include "utility/EndianUtil.h"
#include <string.h>
/**
 * \class GF128 GF128.h <GF128.h>
 * \brief Operations in the Galois field GF(2^128).
 *
 * This class contains helper functions for performing operations in
 * the Galois field GF(2^128) which is used as the basis of GCM and GHASH.
 * These functions are provided for use by other cryptographic protocols
 * that make use of GF(2^128).
 *
 * Most of the functions in this class use the field, polynomial, and
 * byte ordering conventions described in NIST SP 800-38D (GCM).  The one
 * exception is dblEAX() which uses the conventions of EAX mode instead.
 *
 * References: <a href="http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">NIST SP 800-38D</a>
 *
 * \sa GCM, GHASH
 */
/**
 * \brief Initialize multiplication in the GF(2^128) field.
 *
 * \param H The hash state to be initialized.
 * \param key Points to the 16 byte authentication key which is assumed
 * to be in big-endian byte order.
 *
 * This function and the companion mul() are intended for use by other
 * classes that need access to the raw GF(2^128) field multiplication of
 * GHASH without the overhead of GHASH itself.
 *
 * \sa mul(), dbl()
 */
void GF128::mulInit(uint32_t H[4], const void *key)
{
#if defined(__AVR__)
    // Copy the key into H but leave it in big endian order because
    // we can correct for the byte order in mul() below.
    memcpy(H, key, 16);
#else
    // Copy the key into H and convert from big endian to host order.
    memcpy(H, key, 16);
#if defined(CRYPTO_LITTLE_ENDIAN)
    H[0] = be32toh(H[0]);
    H[1] = be32toh(H[1]);
    H[2] = be32toh(H[2]);
    H[3] = be32toh(H[3]);
#endif
#endif
}
/**
 * \brief Perform a multiplication in the GF(2^128) field.
 *
 * \param Y The first value to multiply, and the result.  This array is
 * assumed to be in big-endian order on entry and exit.
 * \param H The second value to multiply, which must have been initialized
 * by the mulInit() function.
 *
 * This function and the companion mulInit() are intended for use by other
 * classes that need access to the raw GF(2^128) field multiplication of
 * GHASH without the overhead of GHASH itself.
 *
 * \sa mulInit(), dbl()
 */
void GF128::mul(uint32_t Y[4], const uint32_t H[4])
{
#if defined(__AVR__)
    uint32_t Z[4] = {0, 0, 0, 0};   // Z = 0
    uint32_t V0 = H[0];             // V = H
    uint32_t V1 = H[1];
    uint32_t V2 = H[2];
    uint32_t V3 = H[3];
    // Multiply Z by V for the set bits in Y, starting at the top.
    // This is a very simple bit by bit version that may not be very
    // fast but it should be resistant to cache timing attacks.
    for (uint8_t posn = 0; posn < 16; ++posn) {
        uint8_t value = ((const uint8_t *)Y)[posn];
        for (uint8_t bit = 0; bit < 8; ++bit) {
            __asm__ __volatile__ (
                // Extract the high bit of "value" and turn it into a mask.
                "ldd r24,%8\n"
                "lsl r24\n"
                "std %8,r24\n"
                "mov __tmp_reg__,__zero_reg__\n"
                "sbc __tmp_reg__,__zero_reg__\n"
                // XOR V with Z if the bit is 1.
                "mov r24,%D0\n"         // Z0 ^= (V0 & mask)
                "and r24,__tmp_reg__\n"
                "ldd r25,%D4\n"
                "eor r25,r24\n"
                "std %D4,r25\n"
                "mov r24,%C0\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%C4\n"
                "eor r25,r24\n"
                "std %C4,r25\n"
                "mov r24,%B0\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%B4\n"
                "eor r25,r24\n"
                "std %B4,r25\n"
                "mov r24,%A0\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%A4\n"
                "eor r25,r24\n"
                "std %A4,r25\n"
                "mov r24,%D1\n"         // Z1 ^= (V1 & mask)
                "and r24,__tmp_reg__\n"
                "ldd r25,%D5\n"
                "eor r25,r24\n"
                "std %D5,r25\n"
                "mov r24,%C1\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%C5\n"
                "eor r25,r24\n"
                "std %C5,r25\n"
                "mov r24,%B1\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%B5\n"
                "eor r25,r24\n"
                "std %B5,r25\n"
                "mov r24,%A1\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%A5\n"
                "eor r25,r24\n"
                "std %A5,r25\n"
                "mov r24,%D2\n"         // Z2 ^= (V2 & mask)
                "and r24,__tmp_reg__\n"
                "ldd r25,%D6\n"
                "eor r25,r24\n"
                "std %D6,r25\n"
                "mov r24,%C2\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%C6\n"
                "eor r25,r24\n"
                "std %C6,r25\n"
                "mov r24,%B2\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%B6\n"
                "eor r25,r24\n"
                "std %B6,r25\n"
                "mov r24,%A2\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%A6\n"
                "eor r25,r24\n"
                "std %A6,r25\n"
                "mov r24,%D3\n"         // Z3 ^= (V3 & mask)
                "and r24,__tmp_reg__\n"
                "ldd r25,%D7\n"
                "eor r25,r24\n"
                "std %D7,r25\n"
                "mov r24,%C3\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%C7\n"
                "eor r25,r24\n"
                "std %C7,r25\n"
                "mov r24,%B3\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%B7\n"
                "eor r25,r24\n"
                "std %B7,r25\n"
                "mov r24,%A3\n"
                "and r24,__tmp_reg__\n"
                "ldd r25,%A7\n"
                "eor r25,r24\n"
                "std %A7,r25\n"
                // Rotate V right by 1 bit.
                "lsr %A0\n"
                "ror %B0\n"
                "ror %C0\n"
                "ror %D0\n"
                "ror %A1\n"
                "ror %B1\n"
                "ror %C1\n"
                "ror %D1\n"
                "ror %A2\n"
                "ror %B2\n"
                "ror %C2\n"
                "ror %D2\n"
                "ror %A3\n"
                "ror %B3\n"
                "ror %C3\n"
                "ror %D3\n"
                "mov r24,__zero_reg__\n"
                "sbc r24,__zero_reg__\n"
                "andi r24,0xE1\n"
                "eor %A0,r24\n"
                : "+r"(V0), "+r"(V1), "+r"(V2), "+r"(V3)
                : "Q"(Z[0]), "Q"(Z[1]), "Q"(Z[2]), "Q"(Z[3]), "Q"(value)
                : "r24", "r25"
            );
        }
    }
    // We have finished the block so copy Z into Y and byte-swap.
    __asm__ __volatile__ (
        "ldd __tmp_reg__,%A0\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%B0\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%C0\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%D0\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%A1\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%B1\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%C1\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%D1\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%A2\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%B2\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%C2\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%D2\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%A3\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%B3\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%C3\n"
        "st X+,__tmp_reg__\n"
        "ldd __tmp_reg__,%D3\n"
        "st X,__tmp_reg__\n"
        : : "Q"(Z[0]), "Q"(Z[1]), "Q"(Z[2]), "Q"(Z[3]), "x"(Y)
    );
#else // !__AVR__
    uint32_t Z0 = 0;        // Z = 0
    uint32_t Z1 = 0;
    uint32_t Z2 = 0;
    uint32_t Z3 = 0;
    uint32_t V0 = H[0];     // V = H
    uint32_t V1 = H[1];
    uint32_t V2 = H[2];
    uint32_t V3 = H[3];
    // Multiply Z by V for the set bits in Y, starting at the top.
    // This is a very simple bit by bit version that may not be very
    // fast but it should be resistant to cache timing attacks.
    for (uint8_t posn = 0; posn < 16; ++posn) {
        uint8_t value = ((const uint8_t *)Y)[posn];
        for (uint8_t bit = 0; bit < 8; ++bit, value <<= 1) {
            // Extract the high bit of "value" and turn it into a mask.
            uint32_t mask = (~((uint32_t)(value >> 7))) + 1;
            // XOR V with Z if the bit is 1.
            Z0 ^= (V0 & mask);
            Z1 ^= (V1 & mask);
            Z2 ^= (V2 & mask);
            Z3 ^= (V3 & mask);
            // Rotate V right by 1 bit.
            mask = ((~(V3 & 0x01)) + 1) & 0xE1000000;
            V3 = (V3 >> 1) | (V2 << 31);
            V2 = (V2 >> 1) | (V1 << 31);
            V1 = (V1 >> 1) | (V0 << 31);
            V0 = (V0 >> 1) ^ mask;
        }
    }
    // We have finished the block so copy Z into Y and byte-swap.
    Y[0] = htobe32(Z0);
    Y[1] = htobe32(Z1);
    Y[2] = htobe32(Z2);
    Y[3] = htobe32(Z3);
#endif // !__AVR__
}
/**
 * \brief Doubles a value in the GF(2^128) field.
 *
 * \param V The value to double, and the result.  This array is
 * assumed to be in big-endian order on entry and exit.
 *
 * Block cipher modes such as <a href="https://en.wikipedia.org/wiki/Disk_encryption_theory#Xor-encrypt-xor_.28XEX.29">XEX</a>
 * are similar to CTR mode but instead of incrementing the nonce every
 * block, the modes multiply the nonce by 2 in the GF(2^128) field every
 * block.  This function is provided to help with implementing such modes.
 *
 * \sa dblEAX(), dblXTS(), mul()
 */
void GF128::dbl(uint32_t V[4])
{
#if defined(__AVR__)
    __asm__ __volatile__ (
        "ld r16,Z\n"
        "ldd r17,Z+1\n"
        "ldd r18,Z+2\n"
        "ldd r19,Z+3\n"
        "lsr r16\n"
        "ror r17\n"
        "ror r18\n"
        "ror r19\n"
        "std Z+1,r17\n"
        "std Z+2,r18\n"
        "std Z+3,r19\n"
        "ldd r17,Z+4\n"
        "ldd r18,Z+5\n"
        "ldd r19,Z+6\n"
        "ldd r20,Z+7\n"
        "ror r17\n"
        "ror r18\n"
        "ror r19\n"
        "ror r20\n"
        "std Z+4,r17\n"
        "std Z+5,r18\n"
        "std Z+6,r19\n"
        "std Z+7,r20\n"
        "ldd r17,Z+8\n"
        "ldd r18,Z+9\n"
        "ldd r19,Z+10\n"
        "ldd r20,Z+11\n"
        "ror r17\n"
        "ror r18\n"
        "ror r19\n"
        "ror r20\n"
        "std Z+8,r17\n"
        "std Z+9,r18\n"
        "std Z+10,r19\n"
        "std Z+11,r20\n"
        "ldd r17,Z+12\n"
        "ldd r18,Z+13\n"
        "ldd r19,Z+14\n"
        "ldd r20,Z+15\n"
        "ror r17\n"
        "ror r18\n"
        "ror r19\n"
        "ror r20\n"
        "std Z+12,r17\n"
        "std Z+13,r18\n"
        "std Z+14,r19\n"
        "std Z+15,r20\n"
        "mov r17,__zero_reg__\n"
        "sbc r17,__zero_reg__\n"
        "andi r17,0xE1\n"
        "eor r16,r17\n"
        "st Z,r16\n"
        : : "z"(V)
        : "r16", "r17", "r18", "r19", "r20"
    );
#else
    uint32_t V0 = be32toh(V[0]);
    uint32_t V1 = be32toh(V[1]);
    uint32_t V2 = be32toh(V[2]);
    uint32_t V3 = be32toh(V[3]);
    uint32_t mask = ((~(V3 & 0x01)) + 1) & 0xE1000000;
    V3 = (V3 >> 1) | (V2 << 31);
    V2 = (V2 >> 1) | (V1 << 31);
    V1 = (V1 >> 1) | (V0 << 31);
    V0 = (V0 >> 1) ^ mask;
    V[0] = htobe32(V0);
    V[1] = htobe32(V1);
    V[2] = htobe32(V2);
    V[3] = htobe32(V3);
#endif
}
/**
 * \brief Doubles a value in the GF(2^128) field using EAX conventions.
 *
 * \param V The value to double, and the result.  This array is
 * assumed to be in big-endian order on entry and exit.
 *
 * This function differs from dbl() that it uses the conventions of EAX mode
 * instead of those of NIST SP 800-38D (GCM).  The two operations have
 * equivalent security but the bits are ordered differently with the
 * value shifted left instead of right.
 *
 * References: https://en.wikipedia.org/wiki/EAX_mode,
 * http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
 *
 * \sa dbl(), dblXTS(), mul()
 */
void GF128::dblEAX(uint32_t V[4])
{
#if defined(__AVR__)
    __asm__ __volatile__ (
        "ldd r16,Z+15\n"
        "ldd r17,Z+14\n"
        "ldd r18,Z+13\n"
        "ldd r19,Z+12\n"
        "lsl r16\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "std Z+14,r17\n"
        "std Z+13,r18\n"
        "std Z+12,r19\n"
        "ldd r17,Z+11\n"
        "ldd r18,Z+10\n"
        "ldd r19,Z+9\n"
        "ldd r20,Z+8\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "rol r20\n"
        "std Z+11,r17\n"
        "std Z+10,r18\n"
        "std Z+9,r19\n"
        "std Z+8,r20\n"
        "ldd r17,Z+7\n"
        "ldd r18,Z+6\n"
        "ldd r19,Z+5\n"
        "ldd r20,Z+4\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "rol r20\n"
        "std Z+7,r17\n"
        "std Z+6,r18\n"
        "std Z+5,r19\n"
        "std Z+4,r20\n"
        "ldd r17,Z+3\n"
        "ldd r18,Z+2\n"
        "ldd r19,Z+1\n"
        "ld r20,Z\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "rol r20\n"
        "std Z+3,r17\n"
        "std Z+2,r18\n"
        "std Z+1,r19\n"
        "st Z,r20\n"
        "mov r17,__zero_reg__\n"
        "sbc r17,__zero_reg__\n"
        "andi r17,0x87\n"
        "eor r16,r17\n"
        "std Z+15,r16\n"
        : : "z"(V)
        : "r16", "r17", "r18", "r19", "r20"
    );
#else
    uint32_t V0 = be32toh(V[0]);
    uint32_t V1 = be32toh(V[1]);
    uint32_t V2 = be32toh(V[2]);
    uint32_t V3 = be32toh(V[3]);
    uint32_t mask = ((~(V0 >> 31)) + 1) & 0x00000087;
    V0 = (V0 << 1) | (V1 >> 31);
    V1 = (V1 << 1) | (V2 >> 31);
    V2 = (V2 << 1) | (V3 >> 31);
    V3 = (V3 << 1) ^ mask;
    V[0] = htobe32(V0);
    V[1] = htobe32(V1);
    V[2] = htobe32(V2);
    V[3] = htobe32(V3);
#endif
}
/**
 * \brief Doubles a value in the GF(2^128) field using XTS conventions.
 *
 * \param V The value to double, and the result.  This array is
 * assumed to be in littlen-endian order on entry and exit.
 *
 * This function differs from dbl() that it uses the conventions of XTS mode
 * instead of those of NIST SP 800-38D (GCM).  The two operations have
 * equivalent security but the bits are ordered differently with the
 * value shifted left instead of right.
 *
 * References: <a href="http://libeccio.di.unisa.it/Crypto14/Lab/p1619.pdf">IEEE Std. 1619-2007, XTS-AES</a>
 *
 * \sa dbl(), dblEAX(), mul()
 */
void GF128::dblXTS(uint32_t V[4])
{
#if defined(__AVR__)
    __asm__ __volatile__ (
        "ld r16,Z\n"
        "ldd r17,Z+1\n"
        "ldd r18,Z+2\n"
        "ldd r19,Z+3\n"
        "lsl r16\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "std Z+1,r17\n"
        "std Z+2,r18\n"
        "std Z+3,r19\n"
        "ldd r17,Z+4\n"
        "ldd r18,Z+5\n"
        "ldd r19,Z+6\n"
        "ldd r20,Z+7\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "rol r20\n"
        "std Z+4,r17\n"
        "std Z+5,r18\n"
        "std Z+6,r19\n"
        "std Z+7,r20\n"
        "ldd r17,Z+8\n"
        "ldd r18,Z+9\n"
        "ldd r19,Z+10\n"
        "ldd r20,Z+11\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "rol r20\n"
        "std Z+8,r17\n"
        "std Z+9,r18\n"
        "std Z+10,r19\n"
        "std Z+11,r20\n"
        "ldd r17,Z+12\n"
        "ldd r18,Z+13\n"
        "ldd r19,Z+14\n"
        "ldd r20,Z+15\n"
        "rol r17\n"
        "rol r18\n"
        "rol r19\n"
        "rol r20\n"
        "std Z+12,r17\n"
        "std Z+13,r18\n"
        "std Z+14,r19\n"
        "std Z+15,r20\n"
        "mov r17,__zero_reg__\n"
        "sbc r17,__zero_reg__\n"
        "andi r17,0x87\n"
        "eor r16,r17\n"
        "st Z,r16\n"
        : : "z"(V)
        : "r16", "r17", "r18", "r19", "r20"
    );
#else
    uint32_t V0 = le32toh(V[0]);
    uint32_t V1 = le32toh(V[1]);
    uint32_t V2 = le32toh(V[2]);
    uint32_t V3 = le32toh(V[3]);
    uint32_t mask = ((~(V3 >> 31)) + 1) & 0x00000087;
    V3 = (V3 << 1) | (V2 >> 31);
    V2 = (V2 << 1) | (V1 >> 31);
    V1 = (V1 << 1) | (V0 >> 31);
    V0 = (V0 << 1) ^ mask;
    V[0] = htole32(V0);
    V[1] = htole32(V1);
    V[2] = htole32(V2);
    V[3] = htole32(V3);
#endif
}
src/modules/Crypto/GF128.h
New file
@@ -0,0 +1,42 @@
/*
 * 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 CRYPTO_GF128_h
#define CRYPTO_GF128_h
#include <inttypes.h>
class GF128
{
private:
    GF128() {}
    ~GF128() {}
public:
    static void mulInit(uint32_t H[4], const void *key);
    static void mul(uint32_t Y[4], const uint32_t H[4]);
    static void dbl(uint32_t V[4]);
    static void dblEAX(uint32_t V[4]);
    static void dblXTS(uint32_t V[4]);
};
#endif
src/modules/Crypto/GHASH.cpp
New file
@@ -0,0 +1,153 @@
/*
 * 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 "GHASH.h"
#include "GF128.h"
#include "Crypto.h"
#include <string.h>
/**
 * \class GHASH GHASH.h <GHASH.h>
 * \brief Implementation of the GHASH message authenticator.
 *
 * GHASH is the message authentication part of Galois Counter Mode (GCM).
 *
 * \note GHASH is not the same as GMAC.  GHASH implements the low level
 * hashing primitive that is used by both GCM and GMAC.  GMAC can be
 * simulated using GCM and an empty plaintext/ciphertext.
 *
 * References: <a href="http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf">NIST SP 800-38D</a>,
 * http://en.wikipedia.org/wiki/Galois/Counter_Mode
 *
 * \sa GCM
 */
/**
 * \brief Constructs a new GHASH message authenticator.
 */
GHASH::GHASH()
{
    state.posn = 0;
}
/**
 * \brief Destroys this GHASH message authenticator.
 */
GHASH::~GHASH()
{
    clean(state);
}
/**
 * \brief Resets the GHASH message authenticator for a new session.
 *
 * \param key Points to the 16 byte authentication key.
 *
 * \sa update(), finalize()
 */
void GHASH::reset(const void *key)
{
    GF128::mulInit(state.H, key);
    memset(state.Y, 0, sizeof(state.Y));
    state.posn = 0;
}
/**
 * \brief Updates the message authenticator with more data.
 *
 * \param data Data to be hashed.
 * \param len Number of bytes of data to be hashed.
 *
 * If finalize() has already been called, then the behavior of update() will
 * be undefined.  Call reset() first to start a new authentication process.
 *
 * \sa pad(), reset(), finalize()
 */
void GHASH::update(const void *data, size_t len)
{
    // XOR the input with state.Y in 128-bit chunks and process them.
    const uint8_t *d = (const uint8_t *)data;
    while (len > 0) {
        uint8_t size = 16 - state.posn;
        if (size > len)
            size = len;
        uint8_t *y = ((uint8_t *)state.Y) + state.posn;
        for (uint8_t i = 0; i < size; ++i)
            y[i] ^= d[i];
        state.posn += size;
        len -= size;
        d += size;
        if (state.posn == 16) {
            GF128::mul(state.Y, state.H);
            state.posn = 0;
        }
    }
}
/**
 * \brief Finalizes the authentication process and returns the token.
 *
 * \param token The buffer to return the token value in.
 * \param len The length of the \a token buffer between 0 and 16.
 *
 * If \a len is less than 16, then the token value will be truncated to
 * the first \a len bytes.  If \a len is greater than 16, then the remaining
 * bytes will left unchanged.
 *
 * If finalize() is called again, then the returned \a token value is
 * undefined.  Call reset() first to start a new authentication process.
 *
 * \sa reset(), update()
 */
void GHASH::finalize(void *token, size_t len)
{
    // Pad with zeroes to a multiple of 16 bytes.
    pad();
    // The token is the current value of Y.
    if (len > 16)
        len = 16;
    memcpy(token, state.Y, len);
}
/**
 * \brief Pads the input stream with zero bytes to a multiple of 16.
 *
 * \sa update()
 */
void GHASH::pad()
{
    if (state.posn != 0) {
        // Padding involves XOR'ing the rest of state.Y with zeroes,
        // which does nothing.  Immediately process the next chunk.
        GF128::mul(state.Y, state.H);
        state.posn = 0;
    }
}
/**
 * \brief Clears the authenticator's state, removing all sensitive data.
 */
void GHASH::clear()
{
    clean(state);
}
src/modules/Crypto/GHASH.h
New file
@@ -0,0 +1,51 @@
/*
 * 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.
 */
#ifndef CRYPTO_GHASH_h
#define CRYPTO_GHASH_h
#include <inttypes.h>
#include <stddef.h>
class GHASH
{
public:
    GHASH();
    ~GHASH();
    void reset(const void *key);
    void update(const void *data, size_t len);
    void finalize(void *token, size_t len);
    void pad();
    void clear();
private:
    struct {
        uint32_t H[4];
        uint32_t Y[4];
        uint8_t posn;
    } state;
};
#endif
src/modules/Crypto/Hash.cpp
New file
@@ -0,0 +1,180 @@
/*
 * 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 "Hash.h"
#include <string.h>
/**
 * \class Hash Hash.h <Hash.h>
 * \brief Abstract base class for cryptographic hash algorithms.
 *
 * \sa SHA256, SHA3_256, BLAKE2s
 */
/**
 * \brief Constructs a new hash object.
 */
Hash::Hash()
{
}
/**
 * \brief Destroys this hash object.
 *
 * \note Subclasses are responsible for clearing any sensitive data
 * that remains in the hash object when it is destroyed.
 *
 * \sa clear()
 */
Hash::~Hash()
{
}
/**
 * \fn size_t Hash::hashSize() const
 * \brief Size of the hash result from finalize().
 *
 * \sa finalize(), blockSize()
 */
/**
 * \fn size_t Hash::blockSize() const
 * \brief Size of the internal block used by the hash algorithm.
 *
 * \sa update(), hashSize()
 */
/**
 * \fn void Hash::reset()
 * \brief Resets the hash ready for a new hashing process.
 *
 * \sa update(), finalize(), resetHMAC()
 */
/**
 * \fn void Hash::update(const void *data, size_t len)
 * \brief Updates the hash with more data.
 *
 * \param data Data to be hashed.
 * \param len Number of bytes of data to be hashed.
 *
 * If finalize() has already been called, then the behavior of update() will
 * be undefined.  Call reset() first to start a new hashing process.
 *
 * \sa reset(), finalize()
 */
/**
 * \fn void Hash::finalize(void *hash, size_t len)
 * \brief Finalizes the hashing process and returns the hash.
 *
 * \param hash The buffer to return the hash value in.
 * \param len The length of the \a hash buffer, normally hashSize().
 *
 * If \a len is less than hashSize(), then the hash value will be
 * truncated to the first \a len bytes.  If \a len is greater than
 * hashSize(), then the remaining bytes will left unchanged.
 *
 * If finalize() is called again, then the returned \a hash value is
 * undefined.  Call reset() first to start a new hashing process.
 *
 * \sa reset(), update(), finalizeHMAC()
 */
/**
 * \fn void Hash::clear()
 * \brief Clears the hash state, removing all sensitive data, and then
 * resets the hash ready for a new hashing process.
 *
 * \sa reset()
 */
/**
 * \fn void Hash::resetHMAC(const void *key, size_t keyLen)
 * \brief Resets the hash ready for a new HMAC hashing process.
 *
 * \param key Points to the HMAC key for the hashing process.
 * \param keyLen Size of the HMAC \a key in bytes.
 *
 * The following example computes a HMAC over a series of data blocks
 * with a specific key:
 *
 * \code
 * hash.resetHMAC(key, sizeof(key));
 * hash.update(data1, sizeof(data1));
 * hash.update(data2, sizeof(data2));
 * ...
 * hash.update(dataN, sizeof(dataN));
 * hash.finalizeHMAC(key, sizeof(key), hmac, sizeof(hmac));
 * \endcode
 *
 * The same key must be passed to both resetHMAC() and finalizeHMAC().
 *
 * \sa finalizeHMAC(), reset()
 */
/**
 * \fn void Hash::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
 * \brief Finalizes the HMAC hashing process and returns the hash.
 *
 * \param key Points to the HMAC key for the hashing process.  The contents
 * of this array must be identical to the value passed to resetHMAC().
 * \param keyLen Size of the HMAC \a key in bytes.
 * \param hash The buffer to return the hash value in.
 * \param hashLen The length of the \a hash buffer, normally hashSize().
 *
 * \sa resetHMAC(), finalize()
 */
/**
 * \brief Formats a HMAC key into a block.
 *
 * \param block The block to format the key into.  Must be at least
 * blockSize() bytes in length.
 * \param key Points to the HMAC key for the hashing process.
 * \param len Length of the HMAC \a key in bytes.
 * \param pad Inner (0x36) or outer (0x5C) padding value to XOR with
 * the formatted HMAC key.
 *
 * This function is intended to help subclasses implement resetHMAC() and
 * finalizeHMAC() by directly formatting the HMAC key into the subclass's
 * internal block buffer and resetting the hash.
 */
void Hash::formatHMACKey(void *block, const void *key, size_t len, uint8_t pad)
{
    size_t size = blockSize();
    reset();
    if (len <= size) {
        memcpy(block, key, len);
    } else {
        update(key, len);
        len = hashSize();
        finalize(block, len);
        reset();
    }
    uint8_t *b = (uint8_t *)block;
    memset(b + len, pad, size - len);
    while (len > 0) {
        *b++ ^= pad;
        --len;
    }
}
src/modules/Crypto/Hash.h
New file
@@ -0,0 +1,51 @@
/*
 * 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.
 */
#ifndef CRYPTO_HASH_h
#define CRYPTO_HASH_h
#include <inttypes.h>
#include <stddef.h>
class Hash
{
public:
    Hash();
    virtual ~Hash();
    virtual size_t hashSize() const = 0;
    virtual size_t blockSize() const = 0;
    virtual void reset() = 0;
    virtual void update(const void *data, size_t len) = 0;
    virtual void finalize(void *hash, size_t len) = 0;
    virtual void clear() = 0;
    virtual void resetHMAC(const void *key, size_t keyLen) = 0;
    virtual void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen) = 0;
protected:
    void formatHMACKey(void *block, const void *key, size_t len, uint8_t pad);
};
#endif
src/modules/Crypto/KeccakCore.cpp
New file
@@ -0,0 +1,2013 @@
/*
 * 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 "KeccakCore.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include "utility/RotateUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
 * \class KeccakCore KeccakCore.h <KeccakCore.h>
 * \brief Keccak core sponge function.
 *
 * KeccakCore provides the core sponge function for different capacities.
 * It is used to implement algorithms such as SHA3 and SHAKE.
 *
 * References: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHA3_256, SHAKE256
 */
#if !defined(CRYPTO_LITTLE_ENDIAN)
// All of the Arduino platforms we care about are little-endian.
#error "KeccakCore is not supported on big-endian platforms yet - todo"
#endif
/**
 * \brief Constructs a new Keccak sponge function.
 *
 * The capacity() will initially be set to 1536, which normally won't be
 * of much use to the caller.  The constructor should be followed by a
 * call to setCapacity() to select the capacity of interest.
 */
KeccakCore::KeccakCore()
    : _blockSize(8)
{
    memset(state.A, 0, sizeof(state.A));
    state.inputSize = 0;
    state.outputSize = 0;
}
/**
 * \brief Destroys this Keccak sponge function after clearing all
 * sensitive information.
 */
KeccakCore::~KeccakCore()
{
    clean(state);
}
/**
 * \brief Returns the capacity of the sponge function in bits.
 *
 * \sa setCapacity(), blockSize()
 */
size_t KeccakCore::capacity() const
{
    return 1600 - ((size_t)_blockSize) * 8;
}
/**
 * \brief Sets the capacity of the Keccak sponge function in bits.
 *
 * \param capacity The capacity of the Keccak sponge function in bits which
 * should be a multiple of 64 and between 64 and 1536.
 *
 * \note It is possible to create a sponge function with this constructor that
 * doesn't strictly conform with the capacity and hash size constraints
 * defined in the relevant standards.  It is the responsibility of callers
 * to only use standard parameter combinations.
 *
 * \sa capacity(), blockSize()
 */
void KeccakCore::setCapacity(size_t capacity)
{
    _blockSize = (1600 - capacity) / 8;
    reset();
}
/**
 * \fn size_t KeccakCore::blockSize() const
 * \brief Returns the input block size for the sponge function in bytes.
 *
 * The block size is (1600 - capacity()) / 8.
 *
 * \sa capacity()
 */
/**
 * \brief Resets the Keccak sponge function ready for a new session.
 *
 * \sa update(), extract()
 */
void KeccakCore::reset()
{
    memset(state.A, 0, sizeof(state.A));
    state.inputSize = 0;
    state.outputSize = 0;
}
/**
 * \brief Updates the Keccak sponge function with more input data.
 *
 * \param data The extra input data to incorporate.
 * \param size The size of the new data to incorporate.
 *
 * This function will invoke the sponge function whenever a full blockSize()
 * bytes of input data have been accumulated.  Call pad() after the last
 * block to finalize the input before calling extract().
 *
 * \sa pad(), extract(), reset()
 */
void KeccakCore::update(const void *data, size_t size)
{
    // Stop generating output while we incorporate the new data.
    state.outputSize = 0;
    // Break the input up into chunks and process each in turn.
    const uint8_t *d = (const uint8_t *)data;
    while (size > 0) {
        uint8_t len = _blockSize - state.inputSize;
        if (len > size)
            len = size;
        uint8_t *Abytes = ((uint8_t *)state.A) + state.inputSize;
        for (uint8_t posn = 0; posn < len; ++posn)
            Abytes[posn] ^= d[posn];
        state.inputSize += len;
        size -= len;
        d += len;
        if (state.inputSize == _blockSize) {
            keccakp();
            state.inputSize = 0;
        }
    }
}
/**
 * \brief Pads the last block of input data to blockSize().
 *
 * \param tag The tag byte to add to the padding to identify SHA3 (0x06),
 * SHAKE (0x1F), or the plain pre-standardized version of Keccak (0x01).
 *
 * The sponge function will be invoked to process the completed padding block.
 *
 * \sa update(), extract()
 */
void KeccakCore::pad(uint8_t tag)
{
    // Padding for SHA3-NNN variants according to FIPS 202 appends "01",
    // then another "1", then many zero bits, followed by a final "1".
    // SHAKE appends "1111" first instead of "01".  Note that SHA-3 numbers
    // bits from the least significant, so appending "01" is equivalent
    // to 0x02 for byte-aligned data, not 0x40.
    uint8_t size = state.inputSize;
    uint64_t *Awords = &(state.A[0][0]);
    Awords[size / 8] ^= (((uint64_t)tag) << ((size % 8) * 8));
    Awords[(_blockSize - 1) / 8] ^= 0x8000000000000000ULL;
    keccakp();
    state.inputSize = 0;
    state.outputSize = 0;
}
/**
 * \brief Extracts data from the Keccak sponge function.
 *
 * \param data The data buffer to fill with extracted data.
 * \param size The number number of bytes of extracted data that are required.
 *
 * If more than blockSize() bytes are required, the sponge function will
 * be invoked to generate additional data.
 *
 * \sa update(), reset(), encrypt()
 */
void KeccakCore::extract(void *data, size_t size)
{
    // Stop accepting input while we are generating output.
    state.inputSize = 0;
    // Copy the output data into the caller's return buffer.
    uint8_t *d = (uint8_t *)data;
    uint8_t tempSize;
    while (size > 0) {
        // Generate another output block if the current one has been exhausted.
        if (state.outputSize >= _blockSize) {
            keccakp();
            state.outputSize = 0;
        }
        // How many bytes can we copy this time around?
        tempSize = _blockSize - state.outputSize;
        if (tempSize > size)
            tempSize = size;
        // Copy the partial output data into the caller's return buffer.
        memcpy(d, ((uint8_t *)(state.A)) + state.outputSize, tempSize);
        state.outputSize += tempSize;
        size -= tempSize;
        d += tempSize;
    }
}
/**
 * \brief Extracts data from the Keccak sponge function and uses it to
 * encrypt a buffer.
 *
 * \param output The output buffer to write to, which may be the same
 * buffer as \a input.  The \a output buffer must have at least as many
 * bytes as the \a input buffer.
 * \param input The input buffer to read from.
 * \param size The number of bytes to encrypt.
 *
 * This function extracts data from the sponge function and then XOR's
 * it with \a input to generate the \a output.
 *
 * If more than blockSize() bytes are required, the sponge function will
 * be invoked to generate additional data.
 *
 * \sa update(), reset(), extract()
 */
void KeccakCore::encrypt(void *output, const void *input, size_t size)
{
    // Stop accepting input while we are generating output.
    state.inputSize = 0;
    // Copy the output data into the caller's return buffer.
    uint8_t *out = (uint8_t *)output;
    const uint8_t *in = (const uint8_t *)input;
    uint8_t tempSize;
    while (size > 0) {
        // Generate another output block if the current one has been exhausted.
        if (state.outputSize >= _blockSize) {
            keccakp();
            state.outputSize = 0;
        }
        // How many bytes can we extract this time around?
        tempSize = _blockSize - state.outputSize;
        if (tempSize > size)
            tempSize = size;
        // XOR the partial output data into the caller's return buffer.
        const uint8_t *d = ((const uint8_t *)(state.A)) + state.outputSize;
        for (uint8_t index = 0; index < tempSize; ++index)
            out[index] = in[index] ^ d[index];
        state.outputSize += tempSize;
        size -= tempSize;
        out += tempSize;
        in += tempSize;
    }
}
/**
 * \brief Clears all sensitive data from this object.
 */
void KeccakCore::clear()
{
    clean(state);
}
/**
 * \brief Sets a HMAC key for a Keccak-based hash algorithm.
 *
 * \param key Points to the HMAC key for the hashing process.
 * \param len Length of the HMAC \a key in bytes.
 * \param pad Inner (0x36) or outer (0x5C) padding value to XOR with
 * the formatted HMAC key.
 * \param hashSize The size of the output from the hash algorithm.
 *
 * This function is intended to help classes implement Hash::resetHMAC() and
 * Hash::finalizeHMAC() by directly formatting the HMAC key into the
 * internal block buffer and resetting the hash.
 */
void KeccakCore::setHMACKey(const void *key, size_t len, uint8_t pad, size_t hashSize)
{
    uint8_t *Abytes = (uint8_t *)state.A;
    size_t size = blockSize();
    reset();
    if (len <= size) {
        // Because the state has just been reset, state.A is set to
        // all-zeroes.  We can copy the key directly into the state
        // and then XOR the block with the pad value.
        memcpy(Abytes, key, len);
    } else {
        // The key is larger than the block size.  Hash it down.
        // Afterwards, state.A will contain the first block of data
        // to be extracted.  We truncate it to the first "hashSize"
        // bytes and XOR with the padding.
        update(key, len);
        this->pad(0x06);
        memset(Abytes + hashSize, pad, size - hashSize);
        memset(Abytes + size, 0, sizeof(state.A) - size);
        size = hashSize;
    }
    while (size > 0) {
        *Abytes++ ^= pad;
        --size;
    }
    keccakp();
}
/**
 * \brief Transform the state with the KECCAK-p sponge function with b = 1600.
 */
void KeccakCore::keccakp()
{
    uint64_t B[5][5];
#if defined(__AVR__)
    // This assembly code was generated by the "genkeccak.c" program.
    // Do not modify this code directly.  Instead modify "genkeccak.c"
    // and then re-generate the code here.
    for (uint8_t round = 0; round < 24; ++round) {
    __asm__ __volatile__ (
        "push r29\n"
        "push r28\n"
        "mov r28,r26\n"
        "mov r29,r27\n"
        // Step mapping theta.  Compute C.
        "ldi r20,5\n"
        "100:\n"
        "ld r8,Z\n"
        "ldd r9,Z+1\n"
        "ldd r10,Z+2\n"
        "ldd r11,Z+3\n"
        "ldd r12,Z+4\n"
        "ldd r13,Z+5\n"
        "ldd r14,Z+6\n"
        "ldd r15,Z+7\n"
        "ldi r19,4\n"
        "101:\n"
        "adiw r30,40\n"
        "ld __tmp_reg__,Z\n"
        "eor r8,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+1\n"
        "eor r9,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+2\n"
        "eor r10,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+3\n"
        "eor r11,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+4\n"
        "eor r12,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+5\n"
        "eor r13,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+6\n"
        "eor r14,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+7\n"
        "eor r15,__tmp_reg__\n"
        "dec r19\n"
        "brne 101b\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "subi r30,152\n"
        "sbc r31,__zero_reg__\n"
        "dec r20\n"
        "brne 100b\n"
        "sbiw r30,40\n"
        "sbiw r26,40\n"
        // Step mapping theta.  Compute D and XOR with A.
        "ldd r8,Y+8\n"
        "ldd r9,Y+9\n"
        "ldd r10,Y+10\n"
        "ldd r11,Y+11\n"
        "ldd r12,Y+12\n"
        "ldd r13,Y+13\n"
        "ldd r14,Y+14\n"
        "ldd r15,Y+15\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "ldd __tmp_reg__,Y+32\n"
        "eor r8,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+33\n"
        "eor r9,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+34\n"
        "eor r10,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+35\n"
        "eor r11,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+36\n"
        "eor r12,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+37\n"
        "eor r13,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+38\n"
        "eor r14,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+39\n"
        "eor r15,__tmp_reg__\n"
        "ldi r19,5\n"
        "103:\n"
        "ld __tmp_reg__,Z\n"
        "eor __tmp_reg__,r8\n"
        "st Z,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+1\n"
        "eor __tmp_reg__,r9\n"
        "std Z+1,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+2\n"
        "eor __tmp_reg__,r10\n"
        "std Z+2,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+3\n"
        "eor __tmp_reg__,r11\n"
        "std Z+3,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+4\n"
        "eor __tmp_reg__,r12\n"
        "std Z+4,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+5\n"
        "eor __tmp_reg__,r13\n"
        "std Z+5,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+6\n"
        "eor __tmp_reg__,r14\n"
        "std Z+6,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+7\n"
        "eor __tmp_reg__,r15\n"
        "std Z+7,__tmp_reg__\n"
        "adiw r30,40\n"
        "dec r19\n"
        "brne 103b\n"
        "subi r30,192\n"
        "sbc r31,__zero_reg__\n"
        "ldd r8,Y+16\n"
        "ldd r9,Y+17\n"
        "ldd r10,Y+18\n"
        "ldd r11,Y+19\n"
        "ldd r12,Y+20\n"
        "ldd r13,Y+21\n"
        "ldd r14,Y+22\n"
        "ldd r15,Y+23\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "ld __tmp_reg__,Y\n"
        "eor r8,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+1\n"
        "eor r9,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+2\n"
        "eor r10,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+3\n"
        "eor r11,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+4\n"
        "eor r12,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+5\n"
        "eor r13,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+6\n"
        "eor r14,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+7\n"
        "eor r15,__tmp_reg__\n"
        "ldi r19,5\n"
        "104:\n"
        "ld __tmp_reg__,Z\n"
        "eor __tmp_reg__,r8\n"
        "st Z,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+1\n"
        "eor __tmp_reg__,r9\n"
        "std Z+1,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+2\n"
        "eor __tmp_reg__,r10\n"
        "std Z+2,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+3\n"
        "eor __tmp_reg__,r11\n"
        "std Z+3,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+4\n"
        "eor __tmp_reg__,r12\n"
        "std Z+4,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+5\n"
        "eor __tmp_reg__,r13\n"
        "std Z+5,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+6\n"
        "eor __tmp_reg__,r14\n"
        "std Z+6,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+7\n"
        "eor __tmp_reg__,r15\n"
        "std Z+7,__tmp_reg__\n"
        "adiw r30,40\n"
        "dec r19\n"
        "brne 104b\n"
        "subi r30,192\n"
        "sbc r31,__zero_reg__\n"
        "ldd r8,Y+24\n"
        "ldd r9,Y+25\n"
        "ldd r10,Y+26\n"
        "ldd r11,Y+27\n"
        "ldd r12,Y+28\n"
        "ldd r13,Y+29\n"
        "ldd r14,Y+30\n"
        "ldd r15,Y+31\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "ldd __tmp_reg__,Y+8\n"
        "eor r8,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+9\n"
        "eor r9,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+10\n"
        "eor r10,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+11\n"
        "eor r11,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+12\n"
        "eor r12,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+13\n"
        "eor r13,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+14\n"
        "eor r14,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+15\n"
        "eor r15,__tmp_reg__\n"
        "ldi r19,5\n"
        "105:\n"
        "ld __tmp_reg__,Z\n"
        "eor __tmp_reg__,r8\n"
        "st Z,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+1\n"
        "eor __tmp_reg__,r9\n"
        "std Z+1,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+2\n"
        "eor __tmp_reg__,r10\n"
        "std Z+2,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+3\n"
        "eor __tmp_reg__,r11\n"
        "std Z+3,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+4\n"
        "eor __tmp_reg__,r12\n"
        "std Z+4,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+5\n"
        "eor __tmp_reg__,r13\n"
        "std Z+5,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+6\n"
        "eor __tmp_reg__,r14\n"
        "std Z+6,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+7\n"
        "eor __tmp_reg__,r15\n"
        "std Z+7,__tmp_reg__\n"
        "adiw r30,40\n"
        "dec r19\n"
        "brne 105b\n"
        "subi r30,192\n"
        "sbc r31,__zero_reg__\n"
        "ldd r8,Y+32\n"
        "ldd r9,Y+33\n"
        "ldd r10,Y+34\n"
        "ldd r11,Y+35\n"
        "ldd r12,Y+36\n"
        "ldd r13,Y+37\n"
        "ldd r14,Y+38\n"
        "ldd r15,Y+39\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "ldd __tmp_reg__,Y+16\n"
        "eor r8,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+17\n"
        "eor r9,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+18\n"
        "eor r10,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+19\n"
        "eor r11,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+20\n"
        "eor r12,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+21\n"
        "eor r13,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+22\n"
        "eor r14,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+23\n"
        "eor r15,__tmp_reg__\n"
        "ldi r19,5\n"
        "106:\n"
        "ld __tmp_reg__,Z\n"
        "eor __tmp_reg__,r8\n"
        "st Z,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+1\n"
        "eor __tmp_reg__,r9\n"
        "std Z+1,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+2\n"
        "eor __tmp_reg__,r10\n"
        "std Z+2,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+3\n"
        "eor __tmp_reg__,r11\n"
        "std Z+3,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+4\n"
        "eor __tmp_reg__,r12\n"
        "std Z+4,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+5\n"
        "eor __tmp_reg__,r13\n"
        "std Z+5,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+6\n"
        "eor __tmp_reg__,r14\n"
        "std Z+6,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+7\n"
        "eor __tmp_reg__,r15\n"
        "std Z+7,__tmp_reg__\n"
        "adiw r30,40\n"
        "dec r19\n"
        "brne 106b\n"
        "subi r30,192\n"
        "sbc r31,__zero_reg__\n"
        "ld r8,Y\n"
        "ldd r9,Y+1\n"
        "ldd r10,Y+2\n"
        "ldd r11,Y+3\n"
        "ldd r12,Y+4\n"
        "ldd r13,Y+5\n"
        "ldd r14,Y+6\n"
        "ldd r15,Y+7\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "ldd __tmp_reg__,Y+24\n"
        "eor r8,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+25\n"
        "eor r9,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+26\n"
        "eor r10,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+27\n"
        "eor r11,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+28\n"
        "eor r12,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+29\n"
        "eor r13,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+30\n"
        "eor r14,__tmp_reg__\n"
        "ldd __tmp_reg__,Y+31\n"
        "eor r15,__tmp_reg__\n"
        "ldi r19,5\n"
        "107:\n"
        "ld __tmp_reg__,Z\n"
        "eor __tmp_reg__,r8\n"
        "st Z,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+1\n"
        "eor __tmp_reg__,r9\n"
        "std Z+1,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+2\n"
        "eor __tmp_reg__,r10\n"
        "std Z+2,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+3\n"
        "eor __tmp_reg__,r11\n"
        "std Z+3,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+4\n"
        "eor __tmp_reg__,r12\n"
        "std Z+4,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+5\n"
        "eor __tmp_reg__,r13\n"
        "std Z+5,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+6\n"
        "eor __tmp_reg__,r14\n"
        "std Z+6,__tmp_reg__\n"
        "ldd __tmp_reg__,Z+7\n"
        "eor __tmp_reg__,r15\n"
        "std Z+7,__tmp_reg__\n"
        "adiw r30,40\n"
        "dec r19\n"
        "brne 107b\n"
        "subi r30,232\n"
        "sbc r31,__zero_reg__\n"
        // Step mappings rho and pi combined into one step.
        // B[0][0] = A[0][0]
        "ld r8,Z\n"
        "ldd r9,Z+1\n"
        "ldd r10,Z+2\n"
        "ldd r11,Z+3\n"
        "ldd r12,Z+4\n"
        "ldd r13,Z+5\n"
        "ldd r14,Z+6\n"
        "ldd r15,Z+7\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        // B[1][0] = leftRotate28_64(A[0][3])
        "adiw r26,32\n"
        "ldd r8,Z+24\n"
        "ldd r9,Z+25\n"
        "ldd r10,Z+26\n"
        "ldd r11,Z+27\n"
        "ldd r12,Z+28\n"
        "ldd r13,Z+29\n"
        "ldd r14,Z+30\n"
        "ldd r15,Z+31\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        // B[2][0] = leftRotate1_64(A[0][1])
        "adiw r26,32\n"
        "ldd r8,Z+8\n"
        "ldd r9,Z+9\n"
        "ldd r10,Z+10\n"
        "ldd r11,Z+11\n"
        "ldd r12,Z+12\n"
        "ldd r13,Z+13\n"
        "ldd r14,Z+14\n"
        "ldd r15,Z+15\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        // B[3][0] = leftRotate27_64(A[0][4])
        "adiw r26,32\n"
        "ldd r8,Z+32\n"
        "ldd r9,Z+33\n"
        "ldd r10,Z+34\n"
        "ldd r11,Z+35\n"
        "ldd r12,Z+36\n"
        "ldd r13,Z+37\n"
        "ldd r14,Z+38\n"
        "ldd r15,Z+39\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        // B[4][0] = leftRotate62_64(A[0][2])
        "adiw r26,32\n"
        "ldd r8,Z+16\n"
        "ldd r9,Z+17\n"
        "ldd r10,Z+18\n"
        "ldd r11,Z+19\n"
        "ldd r12,Z+20\n"
        "ldd r13,Z+21\n"
        "ldd r14,Z+22\n"
        "ldd r15,Z+23\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        // B[0][1] = leftRotate44_64(A[1][1])
        "subi r26,160\n"
        "sbc r27,__zero_reg__\n"
        "adiw r30,40\n"
        "ldd r8,Z+8\n"
        "ldd r9,Z+9\n"
        "ldd r10,Z+10\n"
        "ldd r11,Z+11\n"
        "ldd r12,Z+12\n"
        "ldd r13,Z+13\n"
        "ldd r14,Z+14\n"
        "ldd r15,Z+15\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        // B[1][1] = leftRotate20_64(A[1][4])
        "adiw r26,32\n"
        "ldd r8,Z+32\n"
        "ldd r9,Z+33\n"
        "ldd r10,Z+34\n"
        "ldd r11,Z+35\n"
        "ldd r12,Z+36\n"
        "ldd r13,Z+37\n"
        "ldd r14,Z+38\n"
        "ldd r15,Z+39\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        // B[2][1] = leftRotate6_64(A[1][2])
        "adiw r26,32\n"
        "ldd r8,Z+16\n"
        "ldd r9,Z+17\n"
        "ldd r10,Z+18\n"
        "ldd r11,Z+19\n"
        "ldd r12,Z+20\n"
        "ldd r13,Z+21\n"
        "ldd r14,Z+22\n"
        "ldd r15,Z+23\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        // B[3][1] = leftRotate36_64(A[1][0])
        "adiw r26,32\n"
        "ld r8,Z\n"
        "ldd r9,Z+1\n"
        "ldd r10,Z+2\n"
        "ldd r11,Z+3\n"
        "ldd r12,Z+4\n"
        "ldd r13,Z+5\n"
        "ldd r14,Z+6\n"
        "ldd r15,Z+7\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        // B[4][1] = leftRotate55_64(A[1][3])
        "adiw r26,32\n"
        "ldd r8,Z+24\n"
        "ldd r9,Z+25\n"
        "ldd r10,Z+26\n"
        "ldd r11,Z+27\n"
        "ldd r12,Z+28\n"
        "ldd r13,Z+29\n"
        "ldd r14,Z+30\n"
        "ldd r15,Z+31\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        // B[0][2] = leftRotate43_64(A[2][2])
        "subi r26,160\n"
        "sbc r27,__zero_reg__\n"
        "adiw r30,40\n"
        "ldd r8,Z+16\n"
        "ldd r9,Z+17\n"
        "ldd r10,Z+18\n"
        "ldd r11,Z+19\n"
        "ldd r12,Z+20\n"
        "ldd r13,Z+21\n"
        "ldd r14,Z+22\n"
        "ldd r15,Z+23\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        // B[1][2] = leftRotate3_64(A[2][0])
        "adiw r26,32\n"
        "ld r8,Z\n"
        "ldd r9,Z+1\n"
        "ldd r10,Z+2\n"
        "ldd r11,Z+3\n"
        "ldd r12,Z+4\n"
        "ldd r13,Z+5\n"
        "ldd r14,Z+6\n"
        "ldd r15,Z+7\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        // B[2][2] = leftRotate25_64(A[2][3])
        "adiw r26,32\n"
        "ldd r8,Z+24\n"
        "ldd r9,Z+25\n"
        "ldd r10,Z+26\n"
        "ldd r11,Z+27\n"
        "ldd r12,Z+28\n"
        "ldd r13,Z+29\n"
        "ldd r14,Z+30\n"
        "ldd r15,Z+31\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        // B[3][2] = leftRotate10_64(A[2][1])
        "adiw r26,32\n"
        "ldd r8,Z+8\n"
        "ldd r9,Z+9\n"
        "ldd r10,Z+10\n"
        "ldd r11,Z+11\n"
        "ldd r12,Z+12\n"
        "ldd r13,Z+13\n"
        "ldd r14,Z+14\n"
        "ldd r15,Z+15\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        // B[4][2] = leftRotate39_64(A[2][4])
        "adiw r26,32\n"
        "ldd r8,Z+32\n"
        "ldd r9,Z+33\n"
        "ldd r10,Z+34\n"
        "ldd r11,Z+35\n"
        "ldd r12,Z+36\n"
        "ldd r13,Z+37\n"
        "ldd r14,Z+38\n"
        "ldd r15,Z+39\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        // B[0][3] = leftRotate21_64(A[3][3])
        "subi r26,160\n"
        "sbc r27,__zero_reg__\n"
        "adiw r30,40\n"
        "ldd r8,Z+24\n"
        "ldd r9,Z+25\n"
        "ldd r10,Z+26\n"
        "ldd r11,Z+27\n"
        "ldd r12,Z+28\n"
        "ldd r13,Z+29\n"
        "ldd r14,Z+30\n"
        "ldd r15,Z+31\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        // B[1][3] = leftRotate45_64(A[3][1])
        "adiw r26,32\n"
        "ldd r8,Z+8\n"
        "ldd r9,Z+9\n"
        "ldd r10,Z+10\n"
        "ldd r11,Z+11\n"
        "ldd r12,Z+12\n"
        "ldd r13,Z+13\n"
        "ldd r14,Z+14\n"
        "ldd r15,Z+15\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        // B[2][3] = leftRotate8_64(A[3][4])
        "adiw r26,32\n"
        "ldd r8,Z+32\n"
        "ldd r9,Z+33\n"
        "ldd r10,Z+34\n"
        "ldd r11,Z+35\n"
        "ldd r12,Z+36\n"
        "ldd r13,Z+37\n"
        "ldd r14,Z+38\n"
        "ldd r15,Z+39\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        // B[3][3] = leftRotate15_64(A[3][2])
        "adiw r26,32\n"
        "ldd r8,Z+16\n"
        "ldd r9,Z+17\n"
        "ldd r10,Z+18\n"
        "ldd r11,Z+19\n"
        "ldd r12,Z+20\n"
        "ldd r13,Z+21\n"
        "ldd r14,Z+22\n"
        "ldd r15,Z+23\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        // B[4][3] = leftRotate41_64(A[3][0])
        "adiw r26,32\n"
        "ld r8,Z\n"
        "ldd r9,Z+1\n"
        "ldd r10,Z+2\n"
        "ldd r11,Z+3\n"
        "ldd r12,Z+4\n"
        "ldd r13,Z+5\n"
        "ldd r14,Z+6\n"
        "ldd r15,Z+7\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        // B[0][4] = leftRotate14_64(A[4][4])
        "subi r26,160\n"
        "sbc r27,__zero_reg__\n"
        "adiw r30,40\n"
        "ldd r8,Z+32\n"
        "ldd r9,Z+33\n"
        "ldd r10,Z+34\n"
        "ldd r11,Z+35\n"
        "ldd r12,Z+36\n"
        "ldd r13,Z+37\n"
        "ldd r14,Z+38\n"
        "ldd r15,Z+39\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        // B[1][4] = leftRotate61_64(A[4][2])
        "adiw r26,32\n"
        "ldd r8,Z+16\n"
        "ldd r9,Z+17\n"
        "ldd r10,Z+18\n"
        "ldd r11,Z+19\n"
        "ldd r12,Z+20\n"
        "ldd r13,Z+21\n"
        "ldd r14,Z+22\n"
        "ldd r15,Z+23\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "bst r8,0\n"
        "ror r15\n"
        "ror r14\n"
        "ror r13\n"
        "ror r12\n"
        "ror r11\n"
        "ror r10\n"
        "ror r9\n"
        "ror r8\n"
        "bld r15,7\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        // B[2][4] = leftRotate18_64(A[4][0])
        "adiw r26,32\n"
        "ld r8,Z\n"
        "ldd r9,Z+1\n"
        "ldd r10,Z+2\n"
        "ldd r11,Z+3\n"
        "ldd r12,Z+4\n"
        "ldd r13,Z+5\n"
        "ldd r14,Z+6\n"
        "ldd r15,Z+7\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        // B[3][4] = leftRotate56_64(A[4][3])
        "adiw r26,32\n"
        "ldd r8,Z+24\n"
        "ldd r9,Z+25\n"
        "ldd r10,Z+26\n"
        "ldd r11,Z+27\n"
        "ldd r12,Z+28\n"
        "ldd r13,Z+29\n"
        "ldd r14,Z+30\n"
        "ldd r15,Z+31\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "st X+,r8\n"
        // B[4][4] = leftRotate2_64(A[4][1])
        "adiw r26,32\n"
        "ldd r8,Z+8\n"
        "ldd r9,Z+9\n"
        "ldd r10,Z+10\n"
        "ldd r11,Z+11\n"
        "ldd r12,Z+12\n"
        "ldd r13,Z+13\n"
        "ldd r14,Z+14\n"
        "ldd r15,Z+15\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "lsl r8\n"
        "rol r9\n"
        "rol r10\n"
        "rol r11\n"
        "rol r12\n"
        "rol r13\n"
        "rol r14\n"
        "rol r15\n"
        "adc r8, __zero_reg__\n"
        "st X+,r8\n"
        "st X+,r9\n"
        "st X+,r10\n"
        "st X+,r11\n"
        "st X+,r12\n"
        "st X+,r13\n"
        "st X+,r14\n"
        "st X+,r15\n"
        "subi r26,200\n"
        "sbc r27,__zero_reg__\n"
        "subi r30,160\n"
        "sbc r31,__zero_reg__\n"
        // Step mapping chi.
        "ldi r20,5\n"
        "50:\n"
        "ld r8,Y\n"
        "ldd r9,Y+8\n"
        "ldd r10,Y+16\n"
        "ldd r11,Y+24\n"
        "ldd r12,Y+32\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "st Z,r13\n"
        "std Z+8,r14\n"
        "std Z+16,r15\n"
        "std Z+24,r17\n"
        "std Z+32,r16\n"
        "ldd r8,Y+1\n"
        "ldd r9,Y+9\n"
        "ldd r10,Y+17\n"
        "ldd r11,Y+25\n"
        "ldd r12,Y+33\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+1,r13\n"
        "std Z+9,r14\n"
        "std Z+17,r15\n"
        "std Z+25,r17\n"
        "std Z+33,r16\n"
        "ldd r8,Y+2\n"
        "ldd r9,Y+10\n"
        "ldd r10,Y+18\n"
        "ldd r11,Y+26\n"
        "ldd r12,Y+34\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+2,r13\n"
        "std Z+10,r14\n"
        "std Z+18,r15\n"
        "std Z+26,r17\n"
        "std Z+34,r16\n"
        "ldd r8,Y+3\n"
        "ldd r9,Y+11\n"
        "ldd r10,Y+19\n"
        "ldd r11,Y+27\n"
        "ldd r12,Y+35\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+3,r13\n"
        "std Z+11,r14\n"
        "std Z+19,r15\n"
        "std Z+27,r17\n"
        "std Z+35,r16\n"
        "ldd r8,Y+4\n"
        "ldd r9,Y+12\n"
        "ldd r10,Y+20\n"
        "ldd r11,Y+28\n"
        "ldd r12,Y+36\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+4,r13\n"
        "std Z+12,r14\n"
        "std Z+20,r15\n"
        "std Z+28,r17\n"
        "std Z+36,r16\n"
        "ldd r8,Y+5\n"
        "ldd r9,Y+13\n"
        "ldd r10,Y+21\n"
        "ldd r11,Y+29\n"
        "ldd r12,Y+37\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+5,r13\n"
        "std Z+13,r14\n"
        "std Z+21,r15\n"
        "std Z+29,r17\n"
        "std Z+37,r16\n"
        "ldd r8,Y+6\n"
        "ldd r9,Y+14\n"
        "ldd r10,Y+22\n"
        "ldd r11,Y+30\n"
        "ldd r12,Y+38\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+6,r13\n"
        "std Z+14,r14\n"
        "std Z+22,r15\n"
        "std Z+30,r17\n"
        "std Z+38,r16\n"
        "ldd r8,Y+7\n"
        "ldd r9,Y+15\n"
        "ldd r10,Y+23\n"
        "ldd r11,Y+31\n"
        "ldd r12,Y+39\n"
        "mov r13,r9\n"
        "com r13\n"
        "and r13,r10\n"
        "eor r13,r8\n"
        "mov r14,r10\n"
        "com r14\n"
        "and r14,r11\n"
        "eor r14,r9\n"
        "mov r15,r11\n"
        "com r15\n"
        "and r15,r12\n"
        "eor r15,r10\n"
        "mov r17,r12\n"
        "com r17\n"
        "and r17,r8\n"
        "eor r17,r11\n"
        "mov r16,r8\n"
        "com r16\n"
        "and r16,r9\n"
        "eor r16,r12\n"
        "std Z+7,r13\n"
        "std Z+15,r14\n"
        "std Z+23,r15\n"
        "std Z+31,r17\n"
        "std Z+39,r16\n"
        "adiw r30,40\n"
        "adiw r28,40\n"
        "dec r20\n"
        "breq 51f\n"
        "rjmp 50b\n"
        "51:\n"
        "pop r28\n"
        "pop r29\n"
        // Done
        : : "x"(B), "z"(state.A)
        : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
          "r16", "r17", "r18", "r19", "r20", "r21", "memory"
    );
#else
    static const uint8_t addMod5Table[9] PROGMEM = {
        0, 1, 2, 3, 4, 0, 1, 2, 3
    };
    #define addMod5(x, y) (pgm_read_byte(&(addMod5Table[(x) + (y)])))
    uint64_t D;
    uint8_t index, index2;
    for (uint8_t round = 0; round < 24; ++round) {
        // Step mapping theta.  The specification mentions two temporary
        // arrays of size 5 called C and D.  To save a bit of memory,
        // we use the first row of B to store C and compute D on the fly.
        for (index = 0; index < 5; ++index) {
            B[0][index] = state.A[0][index] ^ state.A[1][index] ^
                          state.A[2][index] ^ state.A[3][index] ^
                          state.A[4][index];
        }
        for (index = 0; index < 5; ++index) {
            D = B[0][addMod5(index, 4)] ^
                leftRotate1_64(B[0][addMod5(index, 1)]);
            for (index2 = 0; index2 < 5; ++index2)
                state.A[index2][index] ^= D;
        }
        // Step mapping rho and pi combined into a single step.
        // Rotate all lanes by a specific offset and rearrange.
        B[0][0] = state.A[0][0];
        B[1][0] = leftRotate28_64(state.A[0][3]);
        B[2][0] = leftRotate1_64 (state.A[0][1]);
        B[3][0] = leftRotate27_64(state.A[0][4]);
        B[4][0] = leftRotate62_64(state.A[0][2]);
        B[0][1] = leftRotate44_64(state.A[1][1]);
        B[1][1] = leftRotate20_64(state.A[1][4]);
        B[2][1] = leftRotate6_64 (state.A[1][2]);
        B[3][1] = leftRotate36_64(state.A[1][0]);
        B[4][1] = leftRotate55_64(state.A[1][3]);
        B[0][2] = leftRotate43_64(state.A[2][2]);
        B[1][2] = leftRotate3_64 (state.A[2][0]);
        B[2][2] = leftRotate25_64(state.A[2][3]);
        B[3][2] = leftRotate10_64(state.A[2][1]);
        B[4][2] = leftRotate39_64(state.A[2][4]);
        B[0][3] = leftRotate21_64(state.A[3][3]);
        B[1][3] = leftRotate45_64(state.A[3][1]);
        B[2][3] = leftRotate8_64 (state.A[3][4]);
        B[3][3] = leftRotate15_64(state.A[3][2]);
        B[4][3] = leftRotate41_64(state.A[3][0]);
        B[0][4] = leftRotate14_64(state.A[4][4]);
        B[1][4] = leftRotate61_64(state.A[4][2]);
        B[2][4] = leftRotate18_64(state.A[4][0]);
        B[3][4] = leftRotate56_64(state.A[4][3]);
        B[4][4] = leftRotate2_64 (state.A[4][1]);
        // Step mapping chi.  Combine each lane with two other lanes in its row.
        for (index = 0; index < 5; ++index) {
            for (index2 = 0; index2 < 5; ++index2) {
                state.A[index2][index] =
                    B[index2][index] ^
                    ((~B[index2][addMod5(index, 1)]) &
                     B[index2][addMod5(index, 2)]);
            }
        }
#endif
        // Step mapping iota.  XOR A[0][0] with the round constant.
        static uint64_t const RC[24] PROGMEM = {
            0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808AULL,
            0x8000000080008000ULL, 0x000000000000808BULL, 0x0000000080000001ULL,
            0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008AULL,
            0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000AULL,
            0x000000008000808BULL, 0x800000000000008BULL, 0x8000000000008089ULL,
            0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
            0x000000000000800AULL, 0x800000008000000AULL, 0x8000000080008081ULL,
            0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
        };
        state.A[0][0] ^= pgm_read_qword(RC + round);
    }
}
src/modules/Crypto/KeccakCore.h
New file
@@ -0,0 +1,63 @@
/*
 * 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.
 */
#ifndef CRYPTO_KECCAKCORE_H
#define CRYPTO_KECCAKCORE_H
#include <inttypes.h>
#include <stddef.h>
class KeccakCore
{
public:
    KeccakCore();
    ~KeccakCore();
    size_t capacity() const;
    void setCapacity(size_t capacity);
    size_t blockSize() const { return _blockSize; }
    void reset();
    void update(const void *data, size_t size);
    void pad(uint8_t tag);
    void extract(void *data, size_t size);
    void encrypt(void *output, const void *input, size_t size);
    void clear();
    void setHMACKey(const void *key, size_t len, uint8_t pad, size_t hashSize);
private:
    struct {
        uint64_t A[5][5];
        uint8_t inputSize;
        uint8_t outputSize;
    } state;
    uint8_t _blockSize;
    void keccakp();
};
#endif
src/modules/Crypto/NoiseSource.cpp
New file
@@ -0,0 +1,120 @@
/*
 * 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 "NoiseSource.h"
#include "RNG.h"
/**
 * \class NoiseSource NoiseSource.h <NoiseSource.h>
 * \brief Abstract base class for random noise sources.
 *
 * \sa \link RNGClass RNG\endlink, TransistorNoiseSource
 */
/**
 * \brief Constructs a new random noise source.
 */
NoiseSource::NoiseSource()
{
}
/**
 * \brief Destroys this random noise source.
 */
NoiseSource::~NoiseSource()
{
}
/**
 * \fn bool NoiseSource::calibrating() const
 * \brief Determine if the noise source is still calibrating itself.
 *
 * \return Returns true if calibration is in progress; false if the noise
 * source is generating valid random data.
 *
 * Noise sources that require calibration start doing so at system startup
 * and then switch over to random data generation once calibration is complete.
 * Since no random data is being generated during calibration, the output
 * from \link RNGClass::rand() RNG.rand()\endlink may be predictable.
 * Use \link RNGClass::available() RNG.available()\endlink to determine
 * when sufficient entropy is available to generate good random values.
 *
 * It is possible that the noise source never exits calibration.  This can
 * happen if the input voltage is insufficient to trigger noise or if the
 * noise source is not connected.  Noise sources may also periodically
 * recalibrate themselves.
 *
 * \sa stir()
 */
/**
 * \fn void NoiseSource::stir()
 * \brief Stirs entropy from this noise source into the global random
 * number pool.
 *
 * This function should call output() to add the entropy from this noise
 * source to the global random number pool.
 *
 * The noise source should batch up the entropy data, providing between
 * 16 and 48 bytes of data each time.  If the noise source does not have
 * sufficient entropy data at the moment, it should return without stiring
 * the current data in.
 *
 * \sa calibrating(), output()
 */
/**
 * \brief Called when the noise source is added to RNG with
 * \link RNGClass::addNoiseSource() RNG.addNoiseSource()\endlink.
 *
 * This function is intended for noise source initialization tasks that
 * must be performed after \link RNGClass::begin() RNG.begin()\endlink
 * has been called to initialize the global random number pool.
 * For example, if the noise source has a unique identifier or serial
 * number then this function can stir it into the pool at startup time.
 */
void NoiseSource::added()
{
    // Nothing to do here.
}
/**
 * \brief Called from subclasses to output noise to the global random
 * number pool.
 *
 * \param data Points to the noise data.
 * \param len Number of bytes of noise data.
 * \param credit The number of bits of entropy to credit for the data.
 * Note that this is bits, not bytes.
 *
 * The default implementation of this function calls
 * \link RNGClass::stir() RNG.stir()\endlink to add the entropy from
 * this noise source to the global random number pool.
 *
 * This function may be overridden by subclasses to capture the raw
 * output from the noise source before it is mixed into the pool to
 * allow the raw data to be analyzed for randomness.
 */
void NoiseSource::output(const uint8_t *data, size_t len, unsigned int credit)
{
    RNG.stir(data, len, credit);
}
src/modules/Crypto/NoiseSource.h
New file
@@ -0,0 +1,44 @@
/*
 * 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.
 */
#ifndef CRYPTO_NOISESOURCE_H
#define CRYPTO_NOISESOURCE_H
#include <inttypes.h>
#include <stddef.h>
class NoiseSource
{
public:
    NoiseSource();
    virtual ~NoiseSource();
    virtual bool calibrating() const = 0;
    virtual void stir() = 0;
    virtual void added();
protected:
    virtual void output(const uint8_t *data, size_t len, unsigned int credit);
};
#endif
src/modules/Crypto/OMAC.cpp
New file
@@ -0,0 +1,200 @@
/*
 * 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 "OMAC.h"
#include "GF128.h"
#include "Crypto.h"
#include <string.h>
/**
 * \class OMAC OMAC.h <OMAC.h>
 * \brief Implementation of the OMAC message authenticator.
 *
 * OMAC is the message authentication part of EAX mode.  It is provided
 * as a separate class for the convenience of applications that need
 * message authentication separate from encryption.
 *
 * References: https://en.wikipedia.org/wiki/EAX_mode,
 * http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
 *
 * \sa EAX
 */
/**
 * \brief Constructs a new OMAC object.
 *
 * This constructor must be followed by a call to setBlockCipher()
 * to specify the block cipher to use.
 */
OMAC::OMAC()
    : _blockCipher(0)
    , posn(0)
{
}
/**
 * \brief Destroys this OMAC object.
 *
 * \sa clear()
 */
OMAC::~OMAC()
{
    clean(b);
}
/**
 * \fn BlockCipher *OMAC::blockCipher() const
 * \brief Gets the block cipher that is in use for this OMAC object.
 *
 * \sa setBlockCipher()
 */
/**
 * \fn void OMAC::setBlockCipher(BlockCipher *cipher)
 * \brief Sets the block cipher to use for this OMAC object.
 *
 * \param cipher The block cipher to use to implement OMAC.
 * This object must have a block size of 128 bits (16 bytes).
 *
 * \sa blockCipher()
 */
/**
 * \brief Initialises the first OMAC hashing context and creates the B value.
 *
 * \param omac The OMAC hashing context.
 *
 * This function must be called first before initNext(), update(), or
 * finalize() to create the B value from the OMAC algorithm which is
 * used to finalize later hashes.  It is assumed that setBlockCipher()
 * has already been called.
 *
 * The tag value for the context is implicitly set to zero, which means
 * that the context can be used for ordinary hashing as long as the
 * data that follows is non-zero in length.  Alternatively, initNext()
 * can be called to restart the context with a specific tag.
 *
 * This function must be called again whenever the block cipher or the
 * key changes.
 *
 * \sa initNext(), update(), finalize()
 */
void OMAC::initFirst(uint8_t omac[16])
{
    // Start the OMAC context.  We assume that the data that follows
    // will be at least 1 byte in length so that we can encrypt the
    // zeroes now to derive the B value.
    memset(omac, 0, 16);
    _blockCipher->encryptBlock(omac, omac);
    posn = 0;
    // Generate the B value from the encrypted block of zeroes.
    // We will need this later when finalising the OMAC hashes.
    memcpy(b, omac, 16);
    GF128::dblEAX(b);
}
/**
 * \brief Initialises or restarts an OMAC hashing context.
 *
 * \param omac The OMAC hashing context.
 * \param tag The tag value indicating which OMAC calculation we are doing.
 *
 * It is assumed that initFirst() was called previously to create the B
 * value for the context.
 *
 * \sa initFirst(), update(), finalize()
 */
void OMAC::initNext(uint8_t omac[16], uint8_t tag)
{
    memset(omac, 0, 15);
    omac[15] = tag;
    posn = 16;
}
/**
 * \brief Updates an OMAC hashing context with more data.
 *
 * \param omac The OMAC hashing context.
 * \param data Points to the data to be hashed.
 * \param size The number of bytes to be hashed.
 *
 * \sa initFirst(), initNext(), finalize()
 */
void OMAC::update(uint8_t omac[16], const uint8_t *data, size_t size)
{
    while (size > 0) {
        // Encrypt the current block if it is already full.
        if (posn == 16) {
            _blockCipher->encryptBlock(omac, omac);
            posn = 0;
        }
        // XOR the incoming data with the current block.
        uint8_t len = 16 - posn;
        if (len > size)
            len = (uint8_t)size;
        for (uint8_t index = 0; index < len; ++index)
            omac[posn++] ^= data[index];
        // Move onto the next block.
        size -= len;
        data += len;
    }
}
/**
 * \brief Finalises an OMAC hashing context.
 *
 * \param omac The OMAC hashing context on entry, the final OMAC value on exit.
 *
 * \sa initFirst(), initNext(), update()
 */
void OMAC::finalize(uint8_t omac[16])
{
    // Apply padding if necessary.
    if (posn != 16) {
        // Need padding: XOR with P = 2 * B.
        uint32_t p[4];
        memcpy(p, b, 16);
        GF128::dblEAX(p);
        omac[posn] ^= 0x80;
        for (uint8_t index = 0; index < 16; ++index)
            omac[index] ^= ((const uint8_t *)p)[index];
        clean(p);
    } else {
        // No padding necessary: XOR with B.
        for (uint8_t index = 0; index < 16; ++index)
            omac[index] ^= ((const uint8_t *)b)[index];
    }
    // Encrypt the hash to get the final OMAC value.
    _blockCipher->encryptBlock(omac, omac);
}
/**
 * \brief Clears all security-sensitive state from this object.
 */
void OMAC::clear()
{
    clean(b);
}
src/modules/Crypto/OMAC.h
New file
@@ -0,0 +1,50 @@
/*
 * 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 CRYPTO_OMAC_H
#define CRYPTO_OMAC_H
#include "BlockCipher.h"
class OMAC
{
public:
    OMAC();
    ~OMAC();
    BlockCipher *blockCipher() const { return _blockCipher; }
    void setBlockCipher(BlockCipher *cipher) { _blockCipher = cipher; }
    void initFirst(uint8_t omac[16]);
    void initNext(uint8_t omac[16], uint8_t tag);
    void update(uint8_t omac[16], const uint8_t *data, size_t size);
    void finalize(uint8_t omac[16]);
    void clear();
private:
    BlockCipher *_blockCipher;
    uint32_t b[4];
    uint8_t posn;
};
#endif
src/modules/Crypto/P521.cpp
New file
@@ -0,0 +1,1642 @@
/*
 * 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 "P521.h"
#include "Crypto.h"
#include "RNG.h"
#include "SHA512.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
 * \class P521 P521.h <P521.h>
 * \brief Elliptic curve operations with the NIST P-521 curve.
 *
 * This class supports both ECDH key exchange and ECDSA signatures.
 *
 * \note The public functions in this class need a substantial amount of
 * stack space to store intermediate results while the curve function is
 * being evaluated.  About 2k of free stack space is recommended for safety.
 *
 * References: NIST FIPS 186-4,
 * <a href="http://tools.ietf.org/html/rfc6090">RFC 6090</a>,
 * <a href="http://tools.ietf.org/html/rfc6979">RFC 6979</a>,
 * <a href="http://tools.ietf.org/html/rfc6090">RFC 5903</a>
 *
 * \sa Curve25519
 */
// Number of limbs that are needed to represent a 521-bit number.
#define NUM_LIMBS_521BIT    NUM_LIMBS_BITS(521)
// Number of limbs that are needed to represent a 1042-bit number.
// To simply things we also require that this be twice the size of
// NUM_LIMB_521BIT which involves a little wastage at the high end
// of one extra limb for 8-bit and 32-bit limbs.  There is no
// wastage for 16-bit limbs.
#define NUM_LIMBS_1042BIT   (NUM_LIMBS_BITS(521) * 2)
// The overhead of clean() calls in mul(), etc can add up to a lot of
// processing time.  Only do such cleanups if strict mode has been enabled.
#if defined(P521_STRICT_CLEAN)
#define strict_clean(x)     clean(x)
#else
#define strict_clean(x)     do { ; } while (0)
#endif
// Expand the partial 9-bit left over limb at the top of a 521-bit number.
#if BIGNUMBER_LIMB_8BIT
#define LIMB_PARTIAL(value) ((uint8_t)(value)), \
                            ((uint8_t)((value) >> 8))
#else
#define LIMB_PARTIAL(value) (value)
#endif
/** @cond */
// The group order "q" value from RFC 4754 and RFC 5903.  This is the
// same as the "n" value from Appendix D.1.2.5 of NIST FIPS 186-4.
static limb_t const P521_q[NUM_LIMBS_521BIT] PROGMEM = {
    LIMB_PAIR(0x91386409, 0xbb6fb71e), LIMB_PAIR(0x899c47ae, 0x3bb5c9b8),
    LIMB_PAIR(0xf709a5d0, 0x7fcc0148), LIMB_PAIR(0xbf2f966b, 0x51868783),
    LIMB_PAIR(0xfffffffa, 0xffffffff), LIMB_PAIR(0xffffffff, 0xffffffff),
    LIMB_PAIR(0xffffffff, 0xffffffff), LIMB_PAIR(0xffffffff, 0xffffffff),
    LIMB_PARTIAL(0x1ff)
};
// The "b" value from Appendix D.1.2.5 of NIST FIPS 186-4.
static limb_t const P521_b[NUM_LIMBS_521BIT] PROGMEM = {
    LIMB_PAIR(0x6b503f00, 0xef451fd4), LIMB_PAIR(0x3d2c34f1, 0x3573df88),
    LIMB_PAIR(0x3bb1bf07, 0x1652c0bd), LIMB_PAIR(0xec7e937b, 0x56193951),
    LIMB_PAIR(0x8ef109e1, 0xb8b48991), LIMB_PAIR(0x99b315f3, 0xa2da725b),
    LIMB_PAIR(0xb68540ee, 0x929a21a0), LIMB_PAIR(0x8e1c9a1f, 0x953eb961),
    LIMB_PARTIAL(0x051)
};
// The "Gx" value from Appendix D.1.2.5 of NIST FIPS 186-4.
static limb_t const P521_Gx[NUM_LIMBS_521BIT] PROGMEM = {
    LIMB_PAIR(0xc2e5bd66, 0xf97e7e31), LIMB_PAIR(0x856a429b, 0x3348b3c1),
    LIMB_PAIR(0xa2ffa8de, 0xfe1dc127), LIMB_PAIR(0xefe75928, 0xa14b5e77),
    LIMB_PAIR(0x6b4d3dba, 0xf828af60), LIMB_PAIR(0x053fb521, 0x9c648139),
    LIMB_PAIR(0x2395b442, 0x9e3ecb66), LIMB_PAIR(0x0404e9cd, 0x858e06b7),
    LIMB_PARTIAL(0x0c6)
};
// The "Gy" value from Appendix D.1.2.5 of NIST FIPS 186-4.
static limb_t const P521_Gy[NUM_LIMBS_521BIT] PROGMEM = {
    LIMB_PAIR(0x9fd16650, 0x88be9476), LIMB_PAIR(0xa272c240, 0x353c7086),
    LIMB_PAIR(0x3fad0761, 0xc550b901), LIMB_PAIR(0x5ef42640, 0x97ee7299),
    LIMB_PAIR(0x273e662c, 0x17afbd17), LIMB_PAIR(0x579b4468, 0x98f54449),
    LIMB_PAIR(0x2c7d1bd9, 0x5c8a5fb4), LIMB_PAIR(0x9a3bc004, 0x39296a78),
    LIMB_PARTIAL(0x118)
};
/** @endcond */
/**
 * \brief Evaluates the curve function.
 *
 * \param result The result of applying the curve function, which consists
 * of the x and y values of the result point encoded in big-endian order.
 * \param f The scalar value to multiply by \a point to create the \a result.
 * This is assumed to be be a 521-bit number in big-endian order.
 * \param point The curve point to multiply consisting of the x and y
 * values encoded in big-endian order.  If \a point is NULL, then the
 * generator Gx and Gy values for the curve will be used instead.
 *
 * \return Returns true if \a f * \a point could be evaluated, or false if
 * \a point is not a point on the curve.
 *
 * This function provides access to the raw curve operation for testing
 * purposes.  Normally an application would use a higher-level function
 * like dh1(), dh2(), sign(), or verify().
 *
 * \sa dh1(), sign()
 */
bool P521::eval(uint8_t result[132], const uint8_t f[66], const uint8_t point[132])
{
    limb_t x[NUM_LIMBS_521BIT];
    limb_t y[NUM_LIMBS_521BIT];
    bool ok;
    // Unpack the curve point from the parameters and validate it.
    if (point) {
        BigNumberUtil::unpackBE(x, NUM_LIMBS_521BIT, point, 66);
        BigNumberUtil::unpackBE(y, NUM_LIMBS_521BIT, point + 66, 66);
        ok = validate(x, y);
    } else {
        memcpy_P(x, P521_Gx, sizeof(x));
        memcpy_P(y, P521_Gy, sizeof(y));
        ok = true;
    }
    // Evaluate the curve function.
    evaluate(x, y, f);
    // Pack the answer into the result array.
    BigNumberUtil::packBE(result, 66, x, NUM_LIMBS_521BIT);
    BigNumberUtil::packBE(result + 66, 66, y, NUM_LIMBS_521BIT);
    // Clean up.
    clean(x);
    clean(y);
    return ok;
}
/**
 * \brief Performs phase 1 of an ECDH key exchange using P-521.
 *
 * \param k The key value to send to the other party as part of the exchange.
 * \param f The generated secret value for this party.  This must not be
 * transmitted to any party or stored in permanent storage.  It only needs
 * to be kept in memory until dh2() is called.
 *
 * The \a f value is generated with \link RNGClass::rand() RNG.rand()\endlink.
 * It is the caller's responsibility to ensure that the global random number
 * pool has sufficient entropy to generate the 66 bytes of \a f safely
 * before calling this function.
 *
 * The following example demonstrates how to perform a full ECDH
 * key exchange using dh1() and dh2():
 *
 * \code
 * uint8_t f[66];
 * uint8_t k[132];
 *
 * // Generate the secret value "f" and the public value "k".
 * P521::dh1(k, f);
 *
 * // Send "k" to the other party.
 * ...
 *
 * // Read the "k" value that the other party sent to us.
 * ...
 *
 * // Generate the shared secret in "f".
 * if (!P521::dh2(k, f)) {
 *     // The received "k" value was invalid - abort the session.
 *     ...
 * }
 *
 * // The "f" value can now be used to generate session keys for encryption.
 * ...
 * \endcode
 *
 * Reference: <a href="http://tools.ietf.org/html/rfc6090">RFC 6090</a>
 *
 * \sa dh2()
 */
void P521::dh1(uint8_t k[132], uint8_t f[66])
{
    generatePrivateKey(f);
    derivePublicKey(k, f);
}
/**
 * \brief Performs phase 2 of an ECDH key exchange using P-521.
 *
 * \param k The public key value that was received from the other
 * party as part of the exchange.
 * \param f On entry, this is the secret value for this party that was
 * generated by dh1().  On exit, this will be the shared secret.
 *
 * \return Returns true if the key exchange was successful, or false if
 * the \a k value is invalid.
 *
 * Reference: <a href="http://tools.ietf.org/html/rfc6090">RFC 6090</a>
 *
 * \sa dh1()
 */
bool P521::dh2(const uint8_t k[132], uint8_t f[66])
{
    // Unpack the (x, y) point from k.
    limb_t x[NUM_LIMBS_521BIT];
    limb_t y[NUM_LIMBS_521BIT];
    BigNumberUtil::unpackBE(x, NUM_LIMBS_521BIT, k, 66);
    BigNumberUtil::unpackBE(y, NUM_LIMBS_521BIT, k + 66, 66);
    // Validate the curve point.  We keep going to preserve the timing.
    bool ok = validate(x, y);
    // Evaluate the curve function.
    evaluate(x, y, f);
    // The secret key is the x component of the final value.
    BigNumberUtil::packBE(f, 66, x, NUM_LIMBS_521BIT);
    // Clean up.
    clean(x);
    clean(y);
    return ok;
}
/**
 * \brief Signs a message using a specific P-521 private key.
 *
 * \param signature The signature value.
 * \param privateKey The private key to use to sign the message.
 * \param message Points to the message to be signed.
 * \param len The length of the \a message to be signed.
 * \param hash The hash algorithm to use to hash the \a message before signing.
 * If \a hash is NULL, then the \a message is assumed to already be a hash
 * value from some previous process.
 *
 * This function generates deterministic ECDSA signatures according to
 * RFC 6979.  The \a hash function is used to generate the k value for
 * the signature.  If \a hash is NULL, then SHA512 is used.
 * The \a hash object must be capable of HMAC mode.
 *
 * The length of the hashed message must be less than or equal to 64
 * bytes in size.  Longer messages will be truncated to 64 bytes.
 *
 * References: <a href="http://tools.ietf.org/html/rfc6090">RFC 6090</a>,
 * <a href="http://tools.ietf.org/html/rfc6979">RFC 6979</a>
 *
 * \sa verify(), generatePrivateKey()
 */
void P521::sign(uint8_t signature[132], const uint8_t privateKey[66],
                const void *message, size_t len, Hash *hash)
{
    uint8_t hm[66];
    uint8_t k[66];
    limb_t x[NUM_LIMBS_521BIT];
    limb_t y[NUM_LIMBS_521BIT];
    limb_t t[NUM_LIMBS_521BIT];
    uint64_t count = 0;
    // Format the incoming message, hashing it if necessary.
    if (hash) {
        // Hash the message.
        hash->reset();
        hash->update(message, len);
        len = hash->hashSize();
        if (len > 64)
            len = 64;
        memset(hm, 0, 66 - len);
        hash->finalize(hm + 66 - len, len);
    } else {
        // The message is the hash.
        if (len > 64)
            len = 64;
        memset(hm, 0, 66 - len);
        memcpy(hm + 66 - len, message, len);
    }
    // Keep generating k values until both r and s are non-zero.
    for (;;) {
        // Generate the k value deterministically according to RFC 6979.
        if (hash)
            generateK(k, hm, privateKey, hash, count);
        else
            generateK(k, hm, privateKey, count);
        // Generate r = kG.x mod q.
        memcpy_P(x, P521_Gx, sizeof(x));
        memcpy_P(y, P521_Gy, sizeof(y));
        evaluate(x, y, k);
        BigNumberUtil::reduceQuick_P(x, x, P521_q, NUM_LIMBS_521BIT);
        BigNumberUtil::packBE(signature, 66, x, NUM_LIMBS_521BIT);
        // If r is zero, then we need to generate a new k value.
        // This is utterly improbable, but let's be safe anyway.
        if (BigNumberUtil::isZero(x, NUM_LIMBS_521BIT)) {
            ++count;
            continue;
        }
        // Generate s = (privateKey * r + hm) / k mod q.
        BigNumberUtil::unpackBE(y, NUM_LIMBS_521BIT, privateKey, 66);
        mulQ(y, y, x);
        BigNumberUtil::unpackBE(x, NUM_LIMBS_521BIT, hm, 66);
        BigNumberUtil::add(x, x, y, NUM_LIMBS_521BIT);
        BigNumberUtil::reduceQuick_P(x, x, P521_q, NUM_LIMBS_521BIT);
        BigNumberUtil::unpackBE(y, NUM_LIMBS_521BIT, k, 66);
        recipQ(t, y);
        mulQ(x, x, t);
        BigNumberUtil::packBE(signature + 66, 66, x, NUM_LIMBS_521BIT);
        // Exit the loop if s is non-zero.
        if (!BigNumberUtil::isZero(x, NUM_LIMBS_521BIT))
            break;
        // We need to generate a new k value according to RFC 6979.
        // This is utterly improbable, but let's be safe anyway.
        ++count;
    }
    // Clean up.
    clean(hm);
    clean(k);
    clean(x);
    clean(y);
    clean(t);
}
/**
 * \brief Verifies a signature using a specific P-521 public key.
 *
 * \param signature The signature value to be verified.
 * \param publicKey The public key to use to verify the signature.
 * \param message The message whose signature is to be verified.
 * \param len The length of the \a message to be verified.
 * \param hash The hash algorithm to use to hash the \a message before
 * verification.  If \a hash is NULL, then the \a message is assumed to
 * already be a hash value from some previous process.
 *
 * The length of the hashed message must be less than or equal to 64
 * bytes in size.  Longer messages will be truncated to 64 bytes.
 *
 * \return Returns true if the \a signature is valid for \a message;
 * or false if the \a publicKey or \a signature is not valid.
 *
 * \sa sign()
 */
bool P521::verify(const uint8_t signature[132],
                  const uint8_t publicKey[132],
                  const void *message, size_t len, Hash *hash)
{
    limb_t x[NUM_LIMBS_521BIT];
    limb_t y[NUM_LIMBS_521BIT];
    limb_t r[NUM_LIMBS_521BIT];
    limb_t s[NUM_LIMBS_521BIT];
    limb_t u1[NUM_LIMBS_521BIT];
    limb_t u2[NUM_LIMBS_521BIT];
    uint8_t t[66];
    bool ok = false;
    // Because we are operating on public values, we don't need to
    // be as strict about constant time.  Bail out early if there
    // is a problem with the parameters.
    // Unpack the signature.  The values must be between 1 and q - 1.
    BigNumberUtil::unpackBE(r, NUM_LIMBS_521BIT, signature, 66);
    BigNumberUtil::unpackBE(s, NUM_LIMBS_521BIT, signature + 66, 66);
    if (BigNumberUtil::isZero(r, NUM_LIMBS_521BIT) ||
            BigNumberUtil::isZero(s, NUM_LIMBS_521BIT) ||
            !BigNumberUtil::sub_P(x, r, P521_q, NUM_LIMBS_521BIT) ||
            !BigNumberUtil::sub_P(x, s, P521_q, NUM_LIMBS_521BIT)) {
        goto failed;
    }
    // Unpack the public key and check that it is a valid curve point.
    BigNumberUtil::unpackBE(x, NUM_LIMBS_521BIT, publicKey, 66);
    BigNumberUtil::unpackBE(y, NUM_LIMBS_521BIT, publicKey + 66, 66);
    if (!validate(x, y)) {
        goto failed;
    }
    // Hash the message to generate hm, which we store into u1.
    if (hash) {
        // Hash the message.
        hash->reset();
        hash->update(message, len);
        len = hash->hashSize();
        if (len > 64)
            len = 64;
        hash->finalize(u2, len);
        BigNumberUtil::unpackBE(u1, NUM_LIMBS_521BIT, (uint8_t *)u2, len);
    } else {
        // The message is the hash.
        if (len > 64)
            len = 64;
        BigNumberUtil::unpackBE(u1, NUM_LIMBS_521BIT, (uint8_t *)message, len);
    }
    // Compute u1 = hm * s^-1 mod q and u2 = r * s^-1 mod q.
    recipQ(u2, s);
    mulQ(u1, u1, u2);
    mulQ(u2, r, u2);
    // Compute the curve point R = u2 * publicKey + u1 * G.
    BigNumberUtil::packBE(t, 66, u2, NUM_LIMBS_521BIT);
    evaluate(x, y, t);
    memcpy_P(u2, P521_Gx, sizeof(x));
    memcpy_P(s, P521_Gy, sizeof(y));
    BigNumberUtil::packBE(t, 66, u1, NUM_LIMBS_521BIT);
    evaluate(u2, s, t);
    addAffine(u2, s, x, y);
    // If R.x = r mod q, then the signature is valid.
    BigNumberUtil::reduceQuick_P(u1, u2, P521_q, NUM_LIMBS_521BIT);
    ok = secure_compare(u1, r, NUM_LIMBS_521BIT * sizeof(limb_t));
    // Clean up and exit.
failed:
    clean(x);
    clean(y);
    clean(r);
    clean(s);
    clean(u1);
    clean(u2);
    clean(t);
    return ok;
}
/**
 * \brief Generates a private key for P-521 signing operations.
 *
 * \param privateKey The resulting private key.
 *
 * The private key is generated with \link RNGClass::rand() RNG.rand()\endlink.
 * It is the caller's responsibility to ensure that the global random number
 * pool has sufficient entropy to generate the 521 bits of the key safely
 * before calling this function.
 *
 * \sa derivePublicKey(), sign()
 */
void P521::generatePrivateKey(uint8_t privateKey[66])
{
    // Generate a random 521-bit value for the private key.  The value
    // must be generated uniformly at random between 1 and q - 1 where q
    // is the group order (RFC 6090).  We use the recommended algorithm
    // from Appendix B of RFC 6090: generate a random 521-bit value
    // and discard it if it is not within the range 1 to q - 1.
    limb_t x[NUM_LIMBS_521BIT];
    do {
        RNG.rand((uint8_t *)x, sizeof(x));
#if BIGNUMBER_LIMB_8BIT
        x[NUM_LIMBS_521BIT - 1] &= 0x01;
#else
        x[NUM_LIMBS_521BIT - 1] &= 0x1FF;
#endif
        BigNumberUtil::packBE(privateKey, 66, x, NUM_LIMBS_521BIT);
    } while (BigNumberUtil::isZero(x, NUM_LIMBS_521BIT) ||
             !BigNumberUtil::sub_P(x, x, P521_q, NUM_LIMBS_521BIT));
    clean(x);
}
/**
 * \brief Derives the public key from a private key for P-521
 * signing operations.
 *
 * \param publicKey The public key.
 * \param privateKey The private key, which is assumed to have been
 * created by generatePrivateKey().
 *
 * \sa generatePrivateKey(), verify()
 */
void P521::derivePublicKey(uint8_t publicKey[132], const uint8_t privateKey[66])
{
    // Evaluate the curve function starting with the generator.
    limb_t x[NUM_LIMBS_521BIT];
    limb_t y[NUM_LIMBS_521BIT];
    memcpy_P(x, P521_Gx, sizeof(x));
    memcpy_P(y, P521_Gy, sizeof(y));
    evaluate(x, y, privateKey);
    // Pack the (x, y) point into the public key.
    BigNumberUtil::packBE(publicKey, 66, x, NUM_LIMBS_521BIT);
    BigNumberUtil::packBE(publicKey + 66, 66, y, NUM_LIMBS_521BIT);
    // Clean up.
    clean(x);
    clean(y);
}
/**
 * \brief Validates a private key value to ensure that it is
 * between 1 and q - 1.
 *
 * \param privateKey The private key value to validate.
 * \return Returns true if \a privateKey is valid, false if not.
 *
 * \sa isValidPublicKey()
 */
bool P521::isValidPrivateKey(const uint8_t privateKey[66])
{
    // The value "q" as a byte array from most to least significant.
    static uint8_t const P521_q_bytes[66] PROGMEM = {
        0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF, 0x2F,
        0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
        0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C,
        0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91, 0x38,
        0x64, 0x09
    };
    uint8_t zeroTest = 0;
    uint8_t posn = 66;
    uint16_t borrow = 0;
    while (posn > 0) {
        --posn;
        // Check for zero.
        zeroTest |= privateKey[posn];
        // Subtract P521_q_bytes from the key.  If there is no borrow,
        // then the key value was greater than or equal to q.
        borrow = ((uint16_t)(privateKey[posn])) -
                 pgm_read_byte(&(P521_q_bytes[posn])) -
                 ((borrow >> 8) & 0x01);
    }
    return zeroTest != 0 && borrow != 0;
}
/**
 * \brief Validates a public key to ensure that it is a valid curve point.
 *
 * \param publicKey The public key value to validate.
 * \return Returns true if \a publicKey is valid, false if not.
 *
 * \sa isValidPrivateKey()
 */
bool P521::isValidPublicKey(const uint8_t publicKey[132])
{
    limb_t x[NUM_LIMBS_521BIT];
    limb_t y[NUM_LIMBS_521BIT];
    BigNumberUtil::unpackBE(x, NUM_LIMBS_521BIT, publicKey, 66);
    BigNumberUtil::unpackBE(y, NUM_LIMBS_521BIT, publicKey + 66, 66);
    bool ok = validate(x, y);
    clean(x);
    clean(y);
    return ok;
}
/**
 * \fn bool P521::isValidCurvePoint(const uint8_t point[132])
 * \brief Validates a point to ensure that it is on the curve.
 *
 * \param point The point to validate.
 * \return Returns true if \a point is valid and on the curve, false if not.
 *
 * This is a convenience function that calls isValidPublicKey() as the
 * two operations are equivalent.
 */
/**
 * \brief Evaluates the curve function by multiplying (x, y) by f.
 *
 * \param x The X co-ordinate of the curve point.  Replaced with the X
 * co-ordinate of the result on exit.
 * \param y The Y co-ordinate of the curve point.  Replaced with the Y
 * co-ordinate of the result on exit.
 * \param f The 521-bit scalar to multiply (x, y) by, most significant
 * bit first.
 */
void P521::evaluate(limb_t *x, limb_t *y, const uint8_t f[66])
{
    limb_t x1[NUM_LIMBS_521BIT];
    limb_t y1[NUM_LIMBS_521BIT];
    limb_t z1[NUM_LIMBS_521BIT];
    limb_t x2[NUM_LIMBS_521BIT];
    limb_t y2[NUM_LIMBS_521BIT];
    limb_t z2[NUM_LIMBS_521BIT];
    // We want the input in Jacobian co-ordinates.  The point (x, y, z)
    // corresponds to the affine point (x / z^2, y / z^3), so if we set z
    // to 1 we end up with Jacobian co-ordinates.  Remember that z is 1
    // and continue on.
    // Set the answer to the point-at-infinity initially (z = 0).
    memset(x1, 0, sizeof(x1));
    memset(y1, 0, sizeof(y1));
    memset(z1, 0, sizeof(z1));
    // Special handling for the highest bit.  We can skip dblPoint()/addPoint()
    // and simply conditionally move (x, y, z) into (x1, y1, z1).
    uint8_t select = (f[0] & 0x01);
    cmove(select, x1, x);
    cmove(select, y1, y);
    cmove1(select, z1); // z = 1
    // Iterate over the remaining 520 bits of f from highest to lowest.
    uint8_t mask = 0x80;
    uint8_t fposn = 1;
    for (uint16_t t = 520; t > 0; --t) {
        // Double the answer.
        dblPoint(x1, y1, z1, x1, y1, z1);
        // Add (x, y, z) to (x1, y1, z1) for the next 1 bit.
        // We must always do this to preserve the overall timing.
        // The z value is always 1 so we can omit that argument.
        addPoint(x2, y2, z2, x1, y1, z1, x, y/*, z*/);
        // If the bit was 1, then move (x2, y2, z2) into (x1, y1, z1).
        select = (f[fposn] & mask);
        cmove(select, x1, x2);
        cmove(select, y1, y2);
        cmove(select, z1, z2);
        // Move onto the next bit.
        mask >>= 1;
        if (!mask) {
            ++fposn;
            mask = 0x80;
        }
    }
    // Convert from Jacobian co-ordinates back into affine co-ordinates.
    // x = x1 * (z1^2)^-1, y = y1 * (z1^3)^-1.
    recip(x2, z1);
    square(y2, x2);
    mul(x, x1, y2);
    mul(y2, y2, x2);
    mul(y, y1, y2);
    // Clean up.
    clean(x1);
    clean(y1);
    clean(z1);
    clean(x2);
    clean(y2);
    clean(z2);
}
/**
 * \brief Adds two affine points.
 *
 * \param x1 The X value for the first point to add, and the result.
 * \param y1 The Y value for the first point to add, and the result.
 * \param x2 The X value for the second point to add.
 * \param y2 The Y value for the second point to add.
 *
 * The Z values for the two points are assumed to be 1.
 */
void P521::addAffine(limb_t *x1, limb_t *y1, const limb_t *x2, const limb_t *y2)
{
    limb_t xout[NUM_LIMBS_521BIT];
    limb_t yout[NUM_LIMBS_521BIT];
    limb_t zout[NUM_LIMBS_521BIT];
    limb_t z1[NUM_LIMBS_521BIT];
    // z1 = 1
    z1[0] = 1;
    memset(z1 + 1, 0, (NUM_LIMBS_521BIT - 1) * sizeof(limb_t));
    // Add the two points.
    addPoint(xout, yout, zout, x1, y1, z1, x2, y2/*, z2*/);
    // Convert from Jacobian co-ordinates back into affine co-ordinates.
    // x1 = xout * (zout^2)^-1, y1 = yout * (zout^3)^-1.
    recip(z1, zout);
    square(zout, z1);
    mul(x1, xout, zout);
    mul(zout, zout, z1);
    mul(y1, yout, zout);
    // Clean up.
    clean(xout);
    clean(yout);
    clean(zout);
    clean(z1);
}
/**
 * \brief Validates that (x, y) is actually a point on the curve.
 *
 * \param x The X co-ordinate of the point to test.
 * \param y The Y co-ordinate of the point to test.
 * \return Returns true if (x, y) is on the curve, or false if not.
 *
 * \sa inRange()
 */
bool P521::validate(const limb_t *x, const limb_t *y)
{
    bool result;
    // If x or y is greater than or equal to 2^521 - 1, then the
    // point is definitely not on the curve.  Preserve timing by
    // delaying the reporting of the result until later.
    result = inRange(x);
    result &= inRange(y);
    // We need to check that y^2 = x^3 - 3 * x + b mod 2^521 - 1.
    limb_t t1[NUM_LIMBS_521BIT];
    limb_t t2[NUM_LIMBS_521BIT];
    square(t1, x);
    mul(t1, t1, x);
    mulLiteral(t2, x, 3);
    sub(t1, t1, t2);
    memcpy_P(t2, P521_b, sizeof(t2));
    add(t1, t1, t2);
    square(t2, y);
    result &= secure_compare(t1, t2, sizeof(t1));
    clean(t1);
    clean(t2);
    return result;
}
/**
 * \brief Determines if a value is between 0 and 2^521 - 2.
 *
 * \param x The value to test.
 * \return Returns true if \a x is in range, false if not.
 *
 * \sa validate()
 */
bool P521::inRange(const limb_t *x)
{
    // Do a trial subtraction of 2^521 - 1 from x, which is equivalent
    // to adding 1 and subtracting 2^521.  We only need the carry.
    dlimb_t carry = 1;
    limb_t word = 0;
    for (uint8_t index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry += *x++;
        word = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // Determine the carry out from the low 521 bits.
#if BIGNUMBER_LIMB_8BIT
    carry = (carry << 7) + (word >> 1);
#else
    carry = (carry << (LIMB_BITS - 9)) + (word >> 9);
#endif
    // If the carry is zero, then x was in range.  Otherwise it is out
    // of range.  Check for zero in a way that preserves constant timing.
    word = (limb_t)(carry | (carry >> LIMB_BITS));
    word = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - word) >> LIMB_BITS);
    return (bool)word;
}
/**
 * \brief Reduces a number modulo 2^521 - 1.
 *
 * \param result The array that will contain the result when the
 * function exits.  Must be NUM_LIMBS_521BIT limbs in size.
 * \param x The number to be reduced, which must be NUM_LIMBS_1042BIT
 * limbs in size and less than square(2^521 - 1).  This array can be
 * the same as \a result.
 */
void P521::reduce(limb_t *result, const limb_t *x)
{
#if BIGNUMBER_LIMB_16BIT || BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
    // According to NIST FIPS 186-4, we add the high 521 bits to the
    // low 521 bits and then do a trial subtraction of 2^521 - 1.
    // We do both in a single step.  Subtracting 2^521 - 1 is equivalent
    // to adding 1 and subtracting 2^521.
    uint8_t index;
    const limb_t *xl = x;
    const limb_t *xh = x + NUM_LIMBS_521BIT;
    limb_t *rr = result;
    dlimb_t carry;
    limb_t word = x[NUM_LIMBS_521BIT - 1];
    carry = (word >> 9) + 1;
    word &= 0x1FF;
    for (index = 0; index < (NUM_LIMBS_521BIT - 1); ++index) {
        carry += *xl++;
        carry += ((dlimb_t)(*xh++)) << (LIMB_BITS - 9);
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    carry += word;
    carry += ((dlimb_t)(x[NUM_LIMBS_1042BIT - 1])) << (LIMB_BITS - 9);
    word = (limb_t)carry;
    *rr = word;
    // If the carry out was 1, then mask it off and we have the answer.
    // If the carry out was 0, then we need to add 2^521 - 1 back again.
    // To preserve the timing we perform a conditional subtract of 1 and
    // then mask off the high bits.
    carry = ((word >> 9) ^ 0x01) & 0x01;
    rr = result;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry = ((dlimb_t)(*rr)) - carry;
        *rr++ = (limb_t)carry;
        carry = (carry >> LIMB_BITS) & 0x01;
    }
    *(--rr) &= 0x1FF;
#elif BIGNUMBER_LIMB_8BIT
    // Same as above, but for 8-bit limbs.
    uint8_t index;
    const limb_t *xl = x;
    const limb_t *xh = x + NUM_LIMBS_521BIT;
    limb_t *rr = result;
    dlimb_t carry;
    limb_t word = x[NUM_LIMBS_521BIT - 1];
    carry = (word >> 1) + 1;
    word &= 0x01;
    for (index = 0; index < (NUM_LIMBS_521BIT - 1); ++index) {
        carry += *xl++;
        carry += ((dlimb_t)(*xh++)) << 7;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    carry += word;
    carry += ((dlimb_t)(x[NUM_LIMBS_1042BIT - 1])) << 1;
    word = (limb_t)carry;
    *rr = word;
    carry = ((word >> 1) ^ 0x01) & 0x01;
    rr = result;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry = ((dlimb_t)(*rr)) - carry;
        *rr++ = (limb_t)carry;
        carry = (carry >> LIMB_BITS) & 0x01;
    }
    *(--rr) &= 0x01;
#else
    #error "Don't know how to reduce values mod 2^521 - 1"
#endif
}
/**
 * \brief Quickly reduces a number modulo 2^521 - 1.
 *
 * \param x The number to be reduced, which must be NUM_LIMBS_521BIT
 * limbs in size and less than or equal to 2 * (2^521 - 2).
 *
 * The answer is also put into \a x and will consist of NUM_LIMBS_521BIT limbs.
 *
 * This function is intended for reducing the result of additions where
 * the caller knows that \a x is within the described range.  A single
 * trial subtraction is all that is needed to reduce the number.
 */
void P521::reduceQuick(limb_t *x)
{
    // Perform a trial subtraction of 2^521 - 1 from x.  This is
    // equivalent to adding 1 and subtracting 2^521 - 1.
    uint8_t index;
    limb_t *xx = x;
    dlimb_t carry = 1;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry += *xx;
        *xx++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // If the carry out was 1, then mask it off and we have the answer.
    // If the carry out was 0, then we need to add 2^521 - 1 back again.
    // To preserve the timing we perform a conditional subtract of 1 and
    // then mask off the high bits.
#if BIGNUMBER_LIMB_16BIT || BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
    carry = ((x[NUM_LIMBS_521BIT - 1] >> 9) ^ 0x01) & 0x01;
    xx = x;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry = ((dlimb_t)(*xx)) - carry;
        *xx++ = (limb_t)carry;
        carry = (carry >> LIMB_BITS) & 0x01;
    }
    *(--xx) &= 0x1FF;
#elif BIGNUMBER_LIMB_8BIT
    carry = ((x[NUM_LIMBS_521BIT - 1] >> 1) ^ 0x01) & 0x01;
    xx = x;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry = ((dlimb_t)(*xx)) - carry;
        *xx++ = (limb_t)carry;
        carry = (carry >> LIMB_BITS) & 0x01;
    }
    *(--xx) &= 0x01;
#endif
}
/**
 * \brief Multiplies two 521-bit values to produce a 1042-bit result.
 *
 * \param result The result, which must be NUM_LIMBS_1042BIT limbs in size
 * and must not overlap with \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_521BIT
 * limbs in size.
 * \param y The second value to multiply, which must be NUM_LIMBS_521BIT
 * limbs in size.
 *
 * \sa mul()
 */
void P521::mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y)
{
    uint8_t i, j;
    dlimb_t carry;
    limb_t word;
    const limb_t *yy;
    limb_t *rr;
    // Multiply the lowest word of x by y.
    carry = 0;
    word = x[0];
    yy = y;
    rr = result;
    for (i = 0; i < NUM_LIMBS_521BIT; ++i) {
        carry += ((dlimb_t)(*yy++)) * word;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    *rr = (limb_t)carry;
    // Multiply and add the remaining words of x by y.
    for (i = 1; i < NUM_LIMBS_521BIT; ++i) {
        word = x[i];
        carry = 0;
        yy = y;
        rr = result + i;
        for (j = 0; j < NUM_LIMBS_521BIT; ++j) {
            carry += ((dlimb_t)(*yy++)) * word;
            carry += *rr;
            *rr++ = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        *rr = (limb_t)carry;
    }
}
/**
 * \brief Multiplies two values and then reduces the result modulo 2^521 - 1.
 *
 * \param result The result, which must be NUM_LIMBS_521BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_521BIT limbs
 * in size and less than 2^521 - 1.
 * \param y The second value to multiply, which must be NUM_LIMBS_521BIT limbs
 * in size and less than 2^521 - 1.  This can be the same array as \a x.
 */
void P521::mul(limb_t *result, const limb_t *x, const limb_t *y)
{
    limb_t temp[NUM_LIMBS_1042BIT];
    mulNoReduce(temp, x, y);
    reduce(result, temp);
    strict_clean(temp);
    crypto_feed_watchdog();
}
/**
 * \fn void P521::square(limb_t *result, const limb_t *x)
 * \brief Squares a value and then reduces it modulo 2^521 - 1.
 *
 * \param result The result, which must be NUM_LIMBS_521BIT limbs in size and
 * can be the same array as \a x.
 * \param x The value to square, which must be NUM_LIMBS_521BIT limbs in size
 * and less than 2^521 - 1.
 */
/**
 * \brief Multiply a value by a single-limb literal modulo 2^521 - 1.
 *
 * \param result The result, which must be NUM_LIMBS_521BIT limbs in size and
 * can be the same array as \a x.
 * \param x The first value to multiply, which must be NUM_LIMBS_521BIT limbs
 * in size and less than 2^521 - 1.
 * \param y The second value to multiply, which must be less than 128.
 */
void P521::mulLiteral(limb_t *result, const limb_t *x, limb_t y)
{
    uint8_t index;
    dlimb_t carry = 0;
    const limb_t *xx = x;
    limb_t *rr = result;
    // Multiply x by the literal and put it into the result array.
    // We assume that y is small enough that overflow from the
    // highest limb will not occur during this process.
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry += ((dlimb_t)(*xx++)) * y;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // Reduce the value modulo 2^521 - 1.  The high half is only a
    // single limb, so we can short-cut some of reduce() here.
#if BIGNUMBER_LIMB_16BIT || BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
    limb_t word = result[NUM_LIMBS_521BIT - 1];
    carry = (word >> 9) + 1;
    word &= 0x1FF;
    rr = result;
    for (index = 0; index < (NUM_LIMBS_521BIT - 1); ++index) {
        carry += *rr;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    carry += word;
    word = (limb_t)carry;
    *rr = word;
    // If the carry out was 1, then mask it off and we have the answer.
    // If the carry out was 0, then we need to add 2^521 - 1 back again.
    // To preserve the timing we perform a conditional subtract of 1 and
    // then mask off the high bits.
    carry = ((word >> 9) ^ 0x01) & 0x01;
    rr = result;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry = ((dlimb_t)(*rr)) - carry;
        *rr++ = (limb_t)carry;
        carry = (carry >> LIMB_BITS) & 0x01;
    }
    *(--rr) &= 0x1FF;
#elif BIGNUMBER_LIMB_8BIT
    // Same as above, but for 8-bit limbs.
    limb_t word = result[NUM_LIMBS_521BIT - 1];
    carry = (word >> 1) + 1;
    word &= 0x01;
    rr = result;
    for (index = 0; index < (NUM_LIMBS_521BIT - 1); ++index) {
        carry += *rr;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    carry += word;
    word = (limb_t)carry;
    *rr = word;
    carry = ((word >> 1) ^ 0x01) & 0x01;
    rr = result;
    for (index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry = ((dlimb_t)(*rr)) - carry;
        *rr++ = (limb_t)carry;
        carry = (carry >> LIMB_BITS) & 0x01;
    }
    *(--rr) &= 0x01;
#endif
}
/**
 * \brief Adds two values and then reduces the result modulo 2^521 - 1.
 *
 * \param result The result, which must be NUM_LIMBS_521BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_521BIT
 * limbs in size and less than 2^521 - 1.
 * \param y The second value to multiply, which must be NUM_LIMBS_521BIT
 * limbs in size and less than 2^521 - 1.
 */
void P521::add(limb_t *result, const limb_t *x, const limb_t *y)
{
    dlimb_t carry = 0;
    limb_t *rr = result;
    for (uint8_t posn = 0; posn < NUM_LIMBS_521BIT; ++posn) {
        carry += *x++;
        carry += *y++;
        *rr++ = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    reduceQuick(result);
}
/**
 * \brief Subtracts two values and then reduces the result modulo 2^521 - 1.
 *
 * \param result The result, which must be NUM_LIMBS_521BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_521BIT
 * limbs in size and less than 2^521 - 1.
 * \param y The second value to multiply, which must be NUM_LIMBS_521BIT
 * limbs in size and less than 2^521 - 1.
 */
void P521::sub(limb_t *result, const limb_t *x, const limb_t *y)
{
    dlimb_t borrow;
    uint8_t posn;
    limb_t *rr = result;
    // Subtract y from x to generate the intermediate result.
    borrow = 0;
    for (posn = 0; posn < NUM_LIMBS_521BIT; ++posn) {
        borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
        *rr++ = (limb_t)borrow;
    }
    // If we had a borrow, then the result has gone negative and we
    // have to add 2^521 - 1 to the result to make it positive again.
    // The top bits of "borrow" will be all 1's if there is a borrow
    // or it will be all 0's if there was no borrow.  Easiest is to
    // conditionally subtract 1 and then mask off the high bits.
    rr = result;
    borrow = (borrow >> LIMB_BITS) & 1U;
    borrow = ((dlimb_t)(*rr)) - borrow;
    *rr++ = (limb_t)borrow;
    for (posn = 1; posn < NUM_LIMBS_521BIT; ++posn) {
        borrow = ((dlimb_t)(*rr)) - ((borrow >> LIMB_BITS) & 0x01);
        *rr++ = (limb_t)borrow;
    }
#if BIGNUMBER_LIMB_8BIT
    *(--rr) &= 0x01;
#else
    *(--rr) &= 0x1FF;
#endif
}
/**
 * \brief Doubles a point represented in Jacobian co-ordinates.
 *
 * \param xout The X value for the result.
 * \param yout The Y value for the result.
 * \param zout The Z value for the result.
 * \param xin The X value for the point to be doubled.
 * \param yin The Y value for the point to be doubled.
 * \param zin The Z value for the point to be doubled.
 *
 * The output parameters can be the same as the input parameters
 * to double in-place.
 *
 * Reference: http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
 */
void P521::dblPoint(limb_t *xout, limb_t *yout, limb_t *zout,
                    const limb_t *xin, const limb_t *yin,
                    const limb_t *zin)
{
    limb_t alpha[NUM_LIMBS_521BIT];
    limb_t beta[NUM_LIMBS_521BIT];
    limb_t gamma[NUM_LIMBS_521BIT];
    limb_t delta[NUM_LIMBS_521BIT];
    limb_t tmp[NUM_LIMBS_521BIT];
    // Double the point.  If it is the point at infinity (z = 0),
    // then zout will still be zero at the end of this process so
    // we don't need any special handling for that case.
    square(delta, zin);       // delta = z^2
    square(gamma, yin);       // gamma = y^2
    mul(beta, xin, gamma);    // beta = x * gamma
    sub(tmp, xin, delta);     // alpha = 3 * (x - delta) * (x + delta)
    mulLiteral(alpha, tmp, 3);
    add(tmp, xin, delta);
    mul(alpha, alpha, tmp);
    square(xout, alpha);      // xout = alpha^2 - 8 * beta
    mulLiteral(tmp, beta, 8);
    sub(xout, xout, tmp);
    add(zout, yin, zin);      // zout = (y + z)^2 - gamma - delta
    square(zout, zout);
    sub(zout, zout, gamma);
    sub(zout, zout, delta);
    mulLiteral(yout, beta, 4);// yout = alpha * (4 * beta - xout) - 8 * gamma^2
    sub(yout, yout, xout);
    mul(yout, alpha, yout);
    square(gamma, gamma);
    mulLiteral(gamma, gamma, 8);
    sub(yout, yout, gamma);
    // Clean up.
    strict_clean(alpha);
    strict_clean(beta);
    strict_clean(gamma);
    strict_clean(delta);
    strict_clean(tmp);
}
/**
 * \brief Adds two curve points, one represented in Jacobian co-ordinates,
 * and the other represented in affine co-ordinates.
 *
 * \param xout The X value for the result.
 * \param yout The Y value for the result.
 * \param zout The Z value for the result.
 * \param x1 The X value for the first point to add.
 * \param y1 The Y value for the first point to add.
 * \param z1 The Z value for the first point to add.
 * \param x2 The X value for the second point to add.
 * \param y2 The Y value for the second point to add.
 *
 * The output parameters must not overlap with either of the inputs.
 *
 * The Z value of the second point is implicitly assumed to be 1.
 *
 * Reference: http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
 */
void P521::addPoint(limb_t *xout, limb_t *yout, limb_t *zout,
                    const limb_t *x1, const limb_t *y1,
                    const limb_t *z1, const limb_t *x2,
                    const limb_t *y2)
{
    limb_t z1z1[NUM_LIMBS_521BIT];
    limb_t u2[NUM_LIMBS_521BIT];
    limb_t s2[NUM_LIMBS_521BIT];
    limb_t h[NUM_LIMBS_521BIT];
    limb_t i[NUM_LIMBS_521BIT];
    limb_t j[NUM_LIMBS_521BIT];
    limb_t r[NUM_LIMBS_521BIT];
    limb_t v[NUM_LIMBS_521BIT];
    // Determine if the first value is the point-at-infinity identity element.
    // The second z value is always 1 so it cannot be the point-at-infinity.
    limb_t p1IsIdentity = BigNumberUtil::isZero(z1, NUM_LIMBS_521BIT);
    // Multiply the points, assuming that z2 = 1.
    square(z1z1, z1);               // z1z1 = z1^2
    mul(u2, x2, z1z1);              // u2 = x2 * z1z1
    mul(s2, y2, z1);                // s2 = y2 * z1 * z1z1
    mul(s2, s2, z1z1);
    sub(h, u2, x1);                 // h = u2 - x1
    mulLiteral(i, h, 2);            // i = (2 * h)^2
    square(i, i);
    sub(r, s2, y1);                 // r = 2 * (s2 - y1)
    add(r, r, r);
    mul(j, h, i);                   // j = h * i
    mul(v, x1, i);                  // v = x1 * i
    square(xout, r);                // xout = r^2 - j - 2 * v
    sub(xout, xout, j);
    sub(xout, xout, v);
    sub(xout, xout, v);
    sub(yout, v, xout);             // yout = r * (v - xout) - 2 * y1 * j
    mul(yout, r, yout);
    mul(j, y1, j);
    sub(yout, yout, j);
    sub(yout, yout, j);
    mul(zout, z1, h);               // zout = 2 * z1 * h
    add(zout, zout, zout);
    // Select the answer to return.  If (x1, y1, z1) was the identity,
    // then the answer is (x2, y2, z2).  Otherwise it is (xout, yout, zout).
    // Conditionally move the second argument over the output if necessary.
    cmove(p1IsIdentity, xout, x2);
    cmove(p1IsIdentity, yout, y2);
    cmove1(p1IsIdentity, zout); // z2 = 1
    // Clean up.
    strict_clean(z1z1);
    strict_clean(u2);
    strict_clean(s2);
    strict_clean(h);
    strict_clean(i);
    strict_clean(j);
    strict_clean(r);
    strict_clean(v);
}
/**
 * \brief Conditionally moves \a y into \a x if a selection value is non-zero.
 *
 * \param select Non-zero to move \a y into \a x, zero to leave \a x unchanged.
 * \param x The destination to move into.
 * \param y The value to conditionally move.
 *
 * The move is performed in a way that it should take the same amount of
 * time irrespective of the value of \a select.
 *
 * \sa cmove1()
 */
void P521::cmove(limb_t select, limb_t *x, const limb_t *y)
{
    uint8_t posn;
    limb_t dummy;
    limb_t sel;
    // Turn "select" into an all-zeroes or all-ones mask.  We don't care
    // which bit or bits is set in the original "select" value.
    sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
    --sel;
    // Move y into x based on "select".
    for (posn = 0; posn < NUM_LIMBS_521BIT; ++posn) {
        dummy = sel & (*x ^ *y++);
        *x++ ^= dummy;
    }
}
/**
 * \brief Conditionally moves 1 into \a x if a selection value is non-zero.
 *
 * \param select Non-zero to move 1 into \a x, zero to leave \a x unchanged.
 * \param x The destination to move into.
 *
 * The move is performed in a way that it should take the same amount of
 * time irrespective of the value of \a select.
 *
 * \sa cmove()
 */
void P521::cmove1(limb_t select, limb_t *x)
{
    uint8_t posn;
    limb_t dummy;
    limb_t sel;
    // Turn "select" into an all-zeroes or all-ones mask.  We don't care
    // which bit or bits is set in the original "select" value.
    sel = (limb_t)(((((dlimb_t)1) << LIMB_BITS) - select) >> LIMB_BITS);
    --sel;
    // Move 1 into x based on "select".
    dummy = sel & (*x ^ 1);
    *x++ ^= dummy;
    for (posn = 1; posn < NUM_LIMBS_521BIT; ++posn) {
        dummy = sel & *x;
        *x++ ^= dummy;
    }
}
/**
 * \brief Computes the reciprocal of a number modulo 2^521 - 1.
 *
 * \param result The result as a array of NUM_LIMBS_521BIT limbs in size.
 * This cannot be the same array as \a x.
 * \param x The number to compute the reciprocal for, also NUM_LIMBS_521BIT
 * limbs in size.
 */
void P521::recip(limb_t *result, const limb_t *x)
{
    limb_t t1[NUM_LIMBS_521BIT];
    // The reciprocal is the same as x ^ (p - 2) where p = 2^521 - 1.
    // The big-endian hexadecimal expansion of (p - 2) is:
    // 01FF FFFFFFF FFFFFFFF ... FFFFFFFF FFFFFFFD
    //
    // The naive implementation needs to do 2 multiplications per 1 bit and
    // 1 multiplication per 0 bit.  We can improve upon this by creating a
    // pattern 1111 and then shifting and multiplying to create 11111111,
    // and then 1111111111111111, and so on for the top 512-bits.
    // Build a 4-bit pattern 1111 in the result.
    square(result, x);
    mul(result, result, x);
    square(result, result);
    mul(result, result, x);
    square(result, result);
    mul(result, result, x);
    // Shift and multiply by increasing powers of two.  This turns
    // 1111 into 11111111, and then 1111111111111111, and so on.
    for (size_t power = 4; power <= 256; power <<= 1) {
        square(t1, result);
        for (size_t temp = 1; temp < power; ++temp)
            square(t1, t1);
        mul(result, result, t1);
    }
    // Handle the 9 lowest bits of (p - 2), 111111101, from highest to lowest.
    for (uint8_t index = 0; index < 7; ++index) {
        square(result, result);
        mul(result, result, x);
    }
    square(result, result);
    square(result, result);
    mul(result, result, x);
    // Clean up.
    clean(t1);
}
/**
 * \brief Reduces a number modulo q.
 *
 * \param result The result array, which must be NUM_LIMBS_521BIT limbs in size.
 * \param r The value to reduce, which must be NUM_LIMBS_1042BIT limbs in size.
 *
 * It is allowed for \a result to be the same as \a r.
 */
void P521::reduceQ(limb_t *result, const limb_t *r)
{
    // Algorithm from: http://en.wikipedia.org/wiki/Barrett_reduction
    //
    // We assume that r is less than or equal to (q - 1)^2.
    //
    // We want to compute result = r mod q.  Find the smallest k such
    // that 2^k > q.  In our case, k = 521.  Then set m = floor(4^k / q)
    // and let r = r - q * floor(m * r / 4^k).  This will be the result
    // or it will be at most one subtraction of q away from the result.
    //
    // Note: m is a 522-bit number, which fits in the same number of limbs
    // as a 521-bit number assuming that limbs are 8 bits or more in size.
    static limb_t const numM[NUM_LIMBS_521BIT] PROGMEM = {
        LIMB_PAIR(0x6EC79BF7, 0x449048E1), LIMB_PAIR(0x7663B851, 0xC44A3647),
        LIMB_PAIR(0x08F65A2F, 0x8033FEB7), LIMB_PAIR(0x40D06994, 0xAE79787C),
        LIMB_PAIR(0x00000005, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000),
        LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000),
        LIMB_PARTIAL(0x200)
    };
    limb_t temp[NUM_LIMBS_1042BIT + NUM_LIMBS_521BIT];
    limb_t temp2[NUM_LIMBS_521BIT];
    // Multiply r by m.
    BigNumberUtil::mul_P(temp, r, NUM_LIMBS_1042BIT, numM, NUM_LIMBS_521BIT);
    // Compute (m * r / 4^521) = (m * r / 2^1042).
#if BIGNUMBER_LIMB_8BIT || BIGNUMBER_LIMB_16BIT
    dlimb_t carry = temp[NUM_LIMBS_BITS(1040)] >> 2;
    for (uint8_t index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry += ((dlimb_t)(temp[NUM_LIMBS_BITS(1040) + index + 1])) << (LIMB_BITS - 2);
        temp2[index] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
#elif BIGNUMBER_LIMB_32BIT || BIGNUMBER_LIMB_64BIT
    dlimb_t carry = temp[NUM_LIMBS_BITS(1024)] >> 18;
    for (uint8_t index = 0; index < NUM_LIMBS_521BIT; ++index) {
        carry += ((dlimb_t)(temp[NUM_LIMBS_BITS(1024) + index + 1])) << (LIMB_BITS - 18);
        temp2[index] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
#endif
    // Multiply (m * r) / 2^1042 by q and subtract it from r.
    // We can ignore the high words of the subtraction result
    // because they will all turn into zero after the subtraction.
    BigNumberUtil::mul_P(temp, temp2, NUM_LIMBS_521BIT,
                         P521_q, NUM_LIMBS_521BIT);
    BigNumberUtil::sub(result, r, temp, NUM_LIMBS_521BIT);
    // Perform a trial subtraction of q from the result to reduce it.
    BigNumberUtil::reduceQuick_P(result, result, P521_q, NUM_LIMBS_521BIT);
    // Clean up and exit.
    clean(temp);
    clean(temp2);
}
/**
 * \brief Multiplies two values and then reduces the result modulo q.
 *
 * \param result The result, which must be NUM_LIMBS_521BIT limbs in size
 * and can be the same array as \a x or \a y.
 * \param x The first value to multiply, which must be NUM_LIMBS_521BIT limbs
 * in size and less than q.
 * \param y The second value to multiply, which must be NUM_LIMBS_521BIT limbs
 * in size and less than q.  This can be the same array as \a x.
 */
void P521::mulQ(limb_t *result, const limb_t *x, const limb_t *y)
{
    limb_t temp[NUM_LIMBS_1042BIT];
    mulNoReduce(temp, x, y);
    reduceQ(result, temp);
    strict_clean(temp);
}
/**
 * \brief Computes the reciprocal of a number modulo q.
 *
 * \param result The result as a array of NUM_LIMBS_521BIT limbs in size.
 * This cannot be the same array as \a x.
 * \param x The number to compute the reciprocal for, also NUM_LIMBS_521BIT
 * limbs in size.
 */
void P521::recipQ(limb_t *result, const limb_t *x)
{
    // Bottom 265 bits of q - 2.  The top 256 bits are all-1's.
    static limb_t const P521_q_m2[] PROGMEM = {
        LIMB_PAIR(0x91386407, 0xbb6fb71e), LIMB_PAIR(0x899c47ae, 0x3bb5c9b8),
        LIMB_PAIR(0xf709a5d0, 0x7fcc0148), LIMB_PAIR(0xbf2f966b, 0x51868783),
        LIMB_PARTIAL(0x1fa)
    };
    // Raise x to the power of q - 2, mod q.  We start with the top
    // 256 bits which are all-1's, using a similar technique to recip().
    limb_t t1[NUM_LIMBS_521BIT];
    mulQ(result, x, x);
    mulQ(result, result, x);
    mulQ(result, result, result);
    mulQ(result, result, x);
    mulQ(result, result, result);
    mulQ(result, result, x);
    for (size_t power = 4; power <= 128; power <<= 1) {
        mulQ(t1, result, result);
        for (size_t temp = 1; temp < power; ++temp)
            mulQ(t1, t1, t1);
        mulQ(result, result, t1);
    }
    clean(t1);
    // Deal with the bottom 265 bits from highest to lowest.  Square for
    // each bit and multiply in x whenever there is a 1 bit.  The timing
    // is based on the publicly-known constant q - 2, not on the value of x.
    size_t bit = 265;
    while (bit > 0) {
        --bit;
        mulQ(result, result, result);
        if (pgm_read_limb(&(P521_q_m2[bit / LIMB_BITS])) &
                (((limb_t)1) << (bit % LIMB_BITS))) {
            mulQ(result, result, x);
        }
    }
}
/**
 * \brief Generates a k value using the algorithm from RFC 6979.
 *
 * \param k The value to generate.
 * \param hm The hashed message formatted ready to be signed.
 * \param x The private key to sign with.
 * \param hash The hash algorithm to use.
 * \param count Iteration counter for generating new values of k when the
 * previous one is rejected.
 */
void P521::generateK(uint8_t k[66], const uint8_t hm[66],
                     const uint8_t x[66], Hash *hash, uint64_t count)
{
    size_t hlen = hash->hashSize();
    uint8_t V[64];
    uint8_t K[64];
    uint8_t marker;
    // If for some reason a hash function was supplied with more than
    // 512 bits of output, truncate hash values to the first 512 bits.
    // We cannot support more than this yet.
    if (hlen > 64)
        hlen = 64;
    // RFC 6979, Section 3.2, Step a.  Hash the message, reduce modulo q,
    // and produce an octet string the same length as q, bits2octets(H(m)).
    // We support hashes up to 512 bits and q is a 521-bit number, so "hm"
    // is already the bits2octets(H(m)) value that we need.
    // Steps b and c.  Set V to all-ones and K to all-zeroes.
    memset(V, 0x01, hlen);
    memset(K, 0x00, hlen);
    // Step d.  K = HMAC_K(V || 0x00 || x || hm).  We make a small
    // modification here to append the count value if it is non-zero.
    // We use this to generate a new k if we have to re-enter this
    // function because the previous one was rejected by sign().
    // This is slightly different to RFC 6979 which says that the
    // loop in step h below should be continued.  That code path is
    // difficult to access, so instead modify K and V in steps d and f.
    // This alternative construction is compatible with the second
    // variant described in section 3.6 of RFC 6979.
    hash->resetHMAC(K, hlen);
    hash->update(V, hlen);
    marker = 0x00;
    hash->update(&marker, 1);
    hash->update(x, 66);
    hash->update(hm, 66);
    if (count)
        hash->update(&count, sizeof(count));
    hash->finalizeHMAC(K, hlen, K, hlen);
    // Step e.  V = HMAC_K(V)
    hash->resetHMAC(K, hlen);
    hash->update(V, hlen);
    hash->finalizeHMAC(K, hlen, V, hlen);
    // Step f.  K = HMAC_K(V || 0x01 || x || hm)
    hash->resetHMAC(K, hlen);
    hash->update(V, hlen);
    marker = 0x01;
    hash->update(&marker, 1);
    hash->update(x, 66);
    hash->update(hm, 66);
    if (count)
        hash->update(&count, sizeof(count));
    hash->finalizeHMAC(K, hlen, K, hlen);
    // Step g.  V = HMAC_K(V)
    hash->resetHMAC(K, hlen);
    hash->update(V, hlen);
    hash->finalizeHMAC(K, hlen, V, hlen);
    // Step h.  Generate candidate k values until we find what we want.
    for (;;) {
        // Step h.1 and h.2.  Generate a string of 66 bytes in length.
        //      T = empty
        //      while (len(T) < 66)
        //          V = HMAC_K(V)
        //          T = T || V
        size_t posn = 0;
        while (posn < 66) {
            size_t temp = 66 - posn;
            if (temp > hlen)
                temp = hlen;
            hash->resetHMAC(K, hlen);
            hash->update(V, hlen);
            hash->finalizeHMAC(K, hlen, V, hlen);
            memcpy(k + posn, V, temp);
            posn += temp;
        }
        // Step h.3.  k = bits2int(T) and exit the loop if k is not in
        // the range 1 to q - 1.  Note: We have to extract the 521 most
        // significant bits of T, which means shifting it right by seven
        // bits to put it into the correct form.
        for (posn = 65; posn > 0; --posn)
            k[posn] = (k[posn - 1] << 1) | (k[posn] >> 7);
        k[0] >>= 7;
        if (isValidPrivateKey(k))
            break;
        // Generate new K and V values and try again.
        //      K = HMAC_K(V || 0x00)
        //      V = HMAC_K(V)
        hash->resetHMAC(K, hlen);
        hash->update(V, hlen);
        marker = 0x00;
        hash->update(&marker, 1);
        hash->finalizeHMAC(K, hlen, K, hlen);
        hash->resetHMAC(K, hlen);
        hash->update(V, hlen);
        hash->finalizeHMAC(K, hlen, V, hlen);
    }
    // Clean up.
    clean(V);
    clean(K);
}
/**
 * \brief Generates a k value using the algorithm from RFC 6979.
 *
 * \param k The value to generate.
 * \param hm The hashed message formatted ready to be signed.
 * \param x The private key to sign with.
 * \param count Iteration counter for generating new values of k when the
 * previous one is rejected.
 *
 * This override uses SHA512 to generate k values.  It is used when
 * sign() was not passed an explicit hash object by the application.
 */
void P521::generateK(uint8_t k[66], const uint8_t hm[66],
                     const uint8_t x[66], uint64_t count)
{
    SHA512 hash;
    generateK(k, hm, x, &hash, count);
}
src/modules/Crypto/P521.h
New file
@@ -0,0 +1,112 @@
/*
 * 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 CRYPTO_P521_h
#define CRYPTO_P521_h
#include "BigNumberUtil.h"
class Hash;
class P521
{
public:
    static bool eval(uint8_t result[132], const uint8_t f[66], const uint8_t point[132]);
    static void dh1(uint8_t k[132], uint8_t f[66]);
    static bool dh2(const uint8_t k[132], uint8_t f[66]);
    static void sign(uint8_t signature[132], const uint8_t privateKey[66],
                     const void *message, size_t len, Hash *hash = 0);
    static bool verify(const uint8_t signature[132],
                       const uint8_t publicKey[132],
                       const void *message, size_t len, Hash *hash = 0);
    static void generatePrivateKey(uint8_t privateKey[66]);
    static void derivePublicKey(uint8_t publicKey[132], const uint8_t privateKey[66]);
    static bool isValidPrivateKey(const uint8_t privateKey[66]);
    static bool isValidPublicKey(const uint8_t publicKey[132]);
    static bool isValidCurvePoint(const uint8_t point[132])
    {
        return isValidPublicKey(point);
    }
#if defined(TEST_P521_FIELD_OPS)
public:
#else
private:
#endif
    static void evaluate(limb_t *x, limb_t *y, const uint8_t f[66]);
    static void addAffine(limb_t *x1, limb_t *y1,
                          const limb_t *x2, const limb_t *y2);
    static bool validate(const limb_t *x, const limb_t *y);
    static bool inRange(const limb_t *x);
    static void reduce(limb_t *result, const limb_t *x);
    static void reduceQuick(limb_t *x);
    static void mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y);
    static void mul(limb_t *result, const limb_t *x, const limb_t *y);
    static void square(limb_t *result, const limb_t *x)
    {
        mul(result, x, x);
    }
    static void mulLiteral(limb_t *result, const limb_t *x, limb_t y);
    static void add(limb_t *result, const limb_t *x, const limb_t *y);
    static void sub(limb_t *result, const limb_t *x, const limb_t *y);
    static void dblPoint(limb_t *xout, limb_t *yout, limb_t *zout,
                         const limb_t *xin, const limb_t *yin,
                         const limb_t *zin);
    static void addPoint(limb_t *xout, limb_t *yout, limb_t *zout,
                         const limb_t *x1, const limb_t *y1,
                         const limb_t *z1, const limb_t *x2,
                         const limb_t *y2);
    static void cmove(limb_t select, limb_t *x, const limb_t *y);
    static void cmove1(limb_t select, limb_t *x);
    static void recip(limb_t *result, const limb_t *x);
    static void reduceQ(limb_t *result, const limb_t *r);
    static void mulQ(limb_t *result, const limb_t *x, const limb_t *y);
    static void recipQ(limb_t *result, const limb_t *x);
    static void generateK(uint8_t k[66], const uint8_t hm[66],
                          const uint8_t x[66], Hash *hash, uint64_t count);
    static void generateK(uint8_t k[66], const uint8_t hm[66],
                          const uint8_t x[66], uint64_t count);
    // Constructor and destructor are private - cannot instantiate this class.
    P521() {}
    ~P521() {}
};
#endif
src/modules/Crypto/Poly1305.cpp
New file
@@ -0,0 +1,345 @@
/*
 * 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 "Poly1305.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
 * \class Poly1305 Poly1305.h <Poly1305.h>
 * \brief Poly1305 message authenticator
 *
 * Poly1305 is a message authenticator designed by Daniel J. Bernstein.
 * An arbitrary-length message is broken up into 16-byte chunks and fed
 * into a polynomial mod 2<sup>130</sup> - 5 based on the 16-byte
 * authentication key.  The final polynomial value is then combined with a
 * 16-byte nonce to create the authentication token.
 *
 * The following example demonstrates how to compute an authentication token
 * for a message made up of several blocks under a specific key and nonce:
 *
 * \code
 * Poly1305 poly1305;
 * uint8_t token[16];
 * poly1305.reset(key);
 * poly1305.update(block1, sizeof(block1));
 * poly1305.update(block2, sizeof(block2));
 * ...
 * poly1305.update(blockN, sizeof(blockN));
 * poly1305.finalize(nonce, token, sizeof(token));
 * \endcode
 *
 * In the original Poly1305 specification, the nonce was encrypted with AES
 * and a second 16-byte key.  Since then, common practice has been for the
 * caller to encrypt the nonce which gives the caller more flexibility as
 * to how to derive and/or encrypt the nonce.
 *
 * References: http://en.wikipedia.org/wiki/Poly1305-AES,
 * http://cr.yp.to/mac.html
 */
// Limb array with enough space for 130 bits.
#define NUM_LIMBS_130BIT    (NUM_LIMBS_128BIT + 1)
// Endian helper macros for limbs and arrays of limbs.
#if BIGNUMBER_LIMB_8BIT
#define lelimbtoh(x)        (x)
#define htolelimb(x)        (x)
#elif BIGNUMBER_LIMB_16BIT
#define lelimbtoh(x)        (le16toh((x)))
#define htolelimb(x)        (htole16((x)))
#elif BIGNUMBER_LIMB_32BIT
#define lelimbtoh(x)        (le32toh((x)))
#define htolelimb(x)        (htole32((x)))
#elif BIGNUMBER_LIMB_64BIT
#define lelimbtoh(x)        (le64toh((x)))
#define htolelimb(x)        (htole64((x)))
#endif
#if defined(CRYPTO_LITTLE_ENDIAN)
#define littleToHost(r,size)    do { ; } while (0)
#else
#define littleToHost(r,size)   \
    do { \
        for (uint8_t i = 0; i < (size); ++i) \
            (r)[i] = lelimbtoh((r)[i]); \
    } while (0)
#endif
/**
 * \brief Constructs a new Poly1305 message authenticator.
 */
Poly1305::Poly1305()
{
    state.chunkSize = 0;
}
/**
 * \brief Destroys this Poly1305 message authenticator after clearing all
 * sensitive information.
 */
Poly1305::~Poly1305()
{
    clean(state);
}
/**
 * \brief Resets the Poly1305 message authenticator for a new session.
 *
 * \param key Points to the 16 byte authentication key.
 *
 * \sa update(), finalize()
 */
void Poly1305::reset(const void *key)
{
    // Copy the key into place and clear the bits we don't need.
    uint8_t *r = (uint8_t *)state.r;
    memcpy(r, key, 16);
    r[3] &= 0x0F;
    r[4] &= 0xFC;
    r[7] &= 0x0F;
    r[8] &= 0xFC;
    r[11] &= 0x0F;
    r[12] &= 0xFC;
    r[15] &= 0x0F;
    // Convert into little-endian if necessary.
    littleToHost(state.r, NUM_LIMBS_128BIT);
    // Reset the hashing process.
    state.chunkSize = 0;
    memset(state.h, 0, sizeof(state.h));
}
/**
 * \brief Updates the message authenticator with more data.
 *
 * \param data Data to be hashed.
 * \param len Number of bytes of data to be hashed.
 *
 * If finalize() has already been called, then the behavior of update() will
 * be undefined.  Call reset() first to start a new authentication process.
 *
 * \sa pad(), reset(), finalize()
 */
void Poly1305::update(const void *data, size_t len)
{
    // Break the input up into 128-bit chunks and process each in turn.
    const uint8_t *d = (const uint8_t *)data;
    while (len > 0) {
        uint8_t size = 16 - state.chunkSize;
        if (size > len)
            size = len;
        memcpy(((uint8_t *)state.c) + state.chunkSize, d, size);
        state.chunkSize += size;
        len -= size;
        d += size;
        if (state.chunkSize == 16) {
            littleToHost(state.c, NUM_LIMBS_128BIT);
            state.c[NUM_LIMBS_128BIT] = 1;
            processChunk();
            state.chunkSize = 0;
        }
    }
}
/**
 * \brief Finalizes the authentication process and returns the token.
 *
 * \param nonce Points to the 16-bit nonce to combine with the token.
 * \param token The buffer to return the token value in.
 * \param len The length of the \a token buffer between 0 and 16.
 *
 * If \a len is less than 16, then the token value will be truncated to
 * the first \a len bytes.  If \a len is greater than 16, then the remaining
 * bytes will left unchanged.
 *
 * If finalize() is called again, then the returned \a token value is
 * undefined.  Call reset() first to start a new authentication process.
 *
 * \sa reset(), update()
 */
void Poly1305::finalize(const void *nonce, void *token, size_t len)
{
    dlimb_t carry;
    uint8_t i;
    limb_t t[NUM_LIMBS_256BIT + 1];
    // Pad and flush the final chunk.
    if (state.chunkSize > 0) {
        uint8_t *c = (uint8_t *)state.c;
        c[state.chunkSize] = 1;
        memset(c + state.chunkSize + 1, 0, 16 - state.chunkSize - 1);
        littleToHost(state.c, NUM_LIMBS_128BIT);
        state.c[NUM_LIMBS_128BIT] = 0;
        processChunk();
    }
    // At this point, processChunk() has left h as a partially reduced
    // result that is less than (2^130 - 5) * 6.  Perform one more
    // reduction and a trial subtraction to produce the final result.
    // Multiply the high bits of h by 5 and add them to the 130 low bits.
    carry = (dlimb_t)((state.h[NUM_LIMBS_128BIT] >> 2) +
                      (state.h[NUM_LIMBS_128BIT] & ~((limb_t)3)));
    state.h[NUM_LIMBS_128BIT] &= 0x0003;
    for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
        carry += state.h[i];
        state.h[i] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    state.h[i] += (limb_t)carry;
    // Subtract (2^130 - 5) from h by computing t = h + 5 - 2^130.
    // The "minus 2^130" step is implicit.
    carry = 5;
    for (i = 0; i < NUM_LIMBS_130BIT; ++i) {
        carry += state.h[i];
        t[i] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // Borrow occurs if bit 2^130 of the previous t result is zero.
    // Carefully turn this into a selection mask so we can select either
    // h or t as the final result.  We don't care about the highest word
    // of the result because we are about to drop it in the next step.
    // We have to do it this way to avoid giving away any information
    // about the value of h in the instruction timing.
    limb_t mask = (~((t[NUM_LIMBS_128BIT] >> 2) & 1)) + 1;
    limb_t nmask = ~mask;
    for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
        state.h[i] = (state.h[i] & nmask) | (t[i] & mask);
    }
    // Add the encrypted nonce and format the final hash.
    memcpy(state.c, nonce, 16);
    littleToHost(state.c, NUM_LIMBS_128BIT);
    carry = 0;
    for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
        carry += state.h[i];
        carry += state.c[i];
        state.h[i] = htolelimb((limb_t)carry);
        carry >>= LIMB_BITS;
    }
    if (len > 16)
        len = 16;
    memcpy(token, state.h, len);
}
/**
 * \brief Pads the input stream with zero bytes to a multiple of 16.
 *
 * \sa update()
 */
void Poly1305::pad()
{
    if (state.chunkSize != 0) {
        memset(((uint8_t *)state.c) + state.chunkSize, 0, 16 - state.chunkSize);
        littleToHost(state.c, NUM_LIMBS_128BIT);
        state.c[NUM_LIMBS_128BIT] = 1;
        processChunk();
        state.chunkSize = 0;
    }
}
/**
 * \brief Clears the authenticator's state, removing all sensitive data.
 */
void Poly1305::clear()
{
    clean(state);
}
/**
 * \brief Processes a single 128-bit chunk of input data.
 */
void Poly1305::processChunk()
{
    limb_t t[NUM_LIMBS_256BIT + 1];
    // Compute h = ((h + c) * r) mod (2^130 - 5).
    // Start with h += c.  We assume that h is less than (2^130 - 5) * 6
    // and that c is less than 2^129, so the result will be less than 2^133.
    dlimb_t carry = 0;
    uint8_t i, j;
    for (i = 0; i < NUM_LIMBS_130BIT; ++i) {
        carry += state.h[i];
        carry += state.c[i];
        state.h[i] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    // Multiply h by r.  We know that r is less than 2^124 because the
    // top 4 bits were AND-ed off by reset().  That makes h * r less
    // than 2^257.  Which is less than the (2^130 - 6)^2 we want for
    // the modulo reduction step that follows.
    carry = 0;
    limb_t word = state.r[0];
    for (i = 0; i < NUM_LIMBS_130BIT; ++i) {
        carry += ((dlimb_t)(state.h[i])) * word;
        t[i] = (limb_t)carry;
        carry >>= LIMB_BITS;
    }
    t[NUM_LIMBS_130BIT] = (limb_t)carry;
    for (i = 1; i < NUM_LIMBS_128BIT; ++i) {
        word = state.r[i];
        carry = 0;
        for (j = 0; j < NUM_LIMBS_130BIT; ++j) {
            carry += ((dlimb_t)(state.h[j])) * word;
            carry += t[i + j];
            t[i + j] = (limb_t)carry;
            carry >>= LIMB_BITS;
        }
        t[i + NUM_LIMBS_130BIT] = (limb_t)carry;
    }
    // Reduce h * r modulo (2^130 - 5) by multiplying the high 130 bits by 5
    // and adding them to the low 130 bits.  See the explaination in the
    // comments for Curve25519::reduce() for a description of how this works.
    carry = ((dlimb_t)(t[NUM_LIMBS_128BIT] >> 2)) +
                      (t[NUM_LIMBS_128BIT] & ~((limb_t)3));
    t[NUM_LIMBS_128BIT] &= 0x0003;
    for (i = 0; i < NUM_LIMBS_128BIT; ++i) {
        // Shift the next word of t up by (LIMB_BITS - 2) bits and then
        // multiply it by 5.  Breaking it down, we can add the results
        // of shifting up by LIMB_BITS and shifting up by (LIMB_BITS - 2).
        // The main wrinkle here is that this can result in an intermediate
        // carry that is (LIMB_BITS * 2 + 1) bits in size which doesn't
        // fit within a dlimb_t variable.  However, we can defer adding
        // (word << LIMB_BITS) until after the "carry >>= LIMB_BITS" step
        // because it won't affect the low bits of the carry.
        word = t[i + NUM_LIMBS_130BIT];
        carry += ((dlimb_t)word) << (LIMB_BITS - 2);
        carry += t[i];
        state.h[i] = (limb_t)carry;
        carry >>= LIMB_BITS;
        carry += word;
    }
    state.h[i] = (limb_t)(carry + t[NUM_LIMBS_128BIT]);
    // At this point, h is either the answer of reducing modulo (2^130 - 5)
    // or it is at most 5 subtractions away from the answer we want.
    // Leave it as-is for now with h less than (2^130 - 5) * 6.  It is
    // still within a range where the next h * r step will not overflow.
}
src/modules/Crypto/Poly1305.h
New file
@@ -0,0 +1,54 @@
/*
 * 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.
 */
#ifndef CRYPTO_POLY1305_h
#define CRYPTO_POLY1305_h
#include "BigNumberUtil.h"
#include <stddef.h>
class Poly1305
{
public:
    Poly1305();
    ~Poly1305();
    void reset(const void *key);
    void update(const void *data, size_t len);
    void finalize(const void *nonce, void *token, size_t len);
    void pad();
    void clear();
private:
    struct {
        limb_t h[(16 / sizeof(limb_t)) + 1];
        limb_t c[(16 / sizeof(limb_t)) + 1];
        limb_t r[(16 / sizeof(limb_t))];
        uint8_t chunkSize;
    } state;
    void processChunk();
};
#endif
src/modules/Crypto/RNG.cpp
New file
@@ -0,0 +1,1004 @@
/*
 * 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 "NoiseSource.h"
#include "ChaCha.h"
#include "Crypto.h"
#include "utility/ProgMemUtil.h"
#include <Arduino.h>
#if defined (__arm__) && defined (__SAM3X8E__)
// The Arduino Due does not have any EEPROM natively on the main chip.
// However, it does have a TRNG and flash memory.
#define RNG_DUE_TRNG 1
#elif defined(__AVR__)
#define RNG_EEPROM 1        // Use EEPROM to save the seed.
#define RNG_WATCHDOG 1      // Harvest entropy from watchdog jitter.
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <avr/io.h>
#define RNG_EEPROM_ADDRESS (E2END + 1 - RNGClass::SEED_SIZE)
#elif defined(ESP8266)
// ESP8266 does not have EEPROM but it does have SPI flash memory.
// It also has a TRNG register for generating "true" random numbers.
// For now we use the TRNG but don't save the seed in flash memory.
#define RNG_WORD_TRNG 1
#define RNG_WORD_TRNG_GET() (ESP8266_DREG(0x20E44))
#elif defined(ESP32)
// ESP32 has a word-based TRNG and an API for Non-Volatile Storage (NVS).
#define RNG_WORD_TRNG 1
#define RNG_WORD_TRNG_GET() (esp_random())
#define RNG_ESP_NVS 1
#include <nvs.h>
#endif
#include <string.h>
// Throw a warning if there is no built-in hardware random number source.
// If this happens, then you need to do one of two things:
//    1. Edit RNG.cpp to add your platform's hardware TRNG.
//    2. Provide a proper noise source like TransistorNoiseSource
//       in your sketch and then comment out the #warning line below.
#if !defined(RNG_DUE_TRNG) && \
    !defined(RNG_WATCHDOG) && \
    !defined(RNG_WORD_TRNG)
#warning "no hardware random number source detected for this platform"
#endif
/**
 * \class RNGClass RNG.h <RNG.h>
 * \brief Pseudo random number generator suitable for cryptography.
 *
 * Random number generators must be seeded properly before they can
 * be used or an adversary may be able to predict the random output.
 * Seed data may be:
 *
 * \li Device-specific, for example serial numbers or MAC addresses.
 * \li Application-specific, unique to the application.  The tag that is
 * passed to begin() is an example of an application-specific value.
 * \li Noise-based, generated by a hardware random number generator
 * that provides unpredictable values from a noise source.
 *
 * The following example demonstrates how to initialise the random
 * number generator:
 *
 * \code
 * #include <SPI.h>
 * #include <Ethernet.h>
 * #include <Crypto.h>
 * #include <RNG.h>
 * #include <TransistorNoiseSource.h>
 *
 * // Noise source to seed the random number generator.
 * TransistorNoiseSource noise(A1);
 *
 * // MAC address for Ethernet communication.
 * byte mac_address[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
 *
 * void setup() {
 *     // Initialize the Ethernet shield.
 *     Ethernet.begin(mac_address);
 *
 *     // Initialize the random number generator with the application tag
 *     // "MyApp 1.0" and load the previous seed from EEPROM.
 *     RNG.begin("MyApp 1.0");
 *
 *     // Stir in the Ethernet MAC address.
 *     RNG.stir(mac_address, sizeof(mac_address));
 *
 *     // Add the noise source to the list of sources known to RNG.
 *     RNG.addNoiseSource(noise);
 *
 *     // ...
 * }
 * \endcode
 *
 * The application should regularly call loop() to stir in new data
 * from the registered noise sources and to periodically save the seed:
 *
 * \code
 * void loop() {
 *     // ...
 *
 *     // Perform regular housekeeping on the random number generator.
 *     RNG.loop();
 *
 *     // ...
 * }
 * \endcode
 *
 * The loop() function will automatically save the random number seed on a
 * regular basis to the last SEED_SIZE bytes of EEPROM memory.  By default
 * the seed is saved every hour but this can be changed using setAutoSaveTime().
 *
 * Keep in mind that saving too often may cause the EEPROM to wear out quicker.
 * It is wise to limit saving to once an hour or once a day depending
 * upon how long you intend to field the device before replacing it.
 * For example, an EEPROM rated for 100k erase/write cycles will last about
 * 69 days saving once a minute or 11 years saving once an hour.
 *
 * The application can still elect to call save() at any time if wants.
 * For example, if the application can detect power loss or shutdown
 * conditions programmatically, then it may make sense to force a save()
 * of the seed upon shutdown.
 *
 * The Arduino Due does not have EEPROM so RNG saves the seed into
 * the last page of system flash memory instead.  The RNG class will also
 * mix in data from the CPU's built-in True Random Number Generator (TRNG).
 * Assuming that the CPU's TRNG is trustworthy, this should be sufficient
 * to properly seed the random number generator.  It is recommended to
 * also mix in data from other noise sources just in case the CPU's TRNG
 * is not trustworthy.
 *
 * \sa NoiseSource
 */
/**
 * \brief Global random number generator instance.
 *
 * \sa RNGClass
 */
RNGClass RNG;
/**
 * \var RNGClass::SEED_SIZE
 * \brief Size of a saved random number seed in EEPROM space.
 *
 * The seed is saved into the last SEED_SIZE bytes of EEPROM memory.
 * The address is dependent upon the size of EEPROM fitted in the device.
 */
// Number of ChaCha hash rounds to use for random number generation.
#define RNG_ROUNDS          20
// Force a rekey after this many blocks of random data.
#define RNG_REKEY_BLOCKS    16
// Maximum entropy credit that can be contained in the pool.
#define RNG_MAX_CREDITS     384u
/** @cond */
// Imported from Crypto.cpp.
extern uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size);
// Tag for 256-bit ChaCha20 keys.  This will always appear in the
// first 16 bytes of the block.  The remaining 48 bytes are the seed.
static const char tagRNG[16] PROGMEM = {
    'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
    '2', '-', 'b', 'y', 't', 'e', ' ', 'k'
};
// Initialization seed.  This is the ChaCha20 output of hashing
// "expand 32-byte k" followed by 48 bytes set to the numbers 1 to 48.
// The ChaCha20 output block is then truncated to the first 48 bytes.
//
// This value is intended to start the RNG in a semi-chaotic state if
// we don't have a previously saved seed in EEPROM.
static const uint8_t initRNG[48] PROGMEM = {
    0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
    0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
    0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
    0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
    0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
    0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
};
#if defined(RNG_WATCHDOG)
// Use jitter between the watchdog timer and the main CPU clock to
// harvest some entropy on AVR-based systems.  This technique comes from:
//
// https://sites.google.com/site/astudyofentropy/project-definition/timer-jitter-entropy-sources/entropy-library
//
// The watchdog generates entropy very slowly - it can take around 32 seconds
// to generate 256 bits of entropy credit.  This is a "better than nothing"
// entropy source but a real noise source is definitely recommended.
// Helper macros for specific 32-bit shift counts.
#define leftShift3(value)   ((value) << 3)
#define leftShift10(value)  ((value) << 10)
#define leftShift15(value)  ((value) << 15)
#define rightShift6(value)  ((value) >> 6)
#define rightShift11(value) ((value) >> 11)
static uint32_t volatile hash = 0;
static uint8_t volatile outBits = 0;
// Watchdog interrupt handler.  This fires off every 16ms.  We collect
// 32 bits and then pass them off onto RNGClass::loop().
ISR(WDT_vect)
{
    // Read the low byte of Timer 1.  We assume that the timer was
    // initialized by the Arduino startup code for PWM use or that the
    // application is free-running Timer 1 for its own purposes.
    // Timer 0 is used on systems that don't have a Timer 1.
#if defined(TCNT1L)
    unsigned char value = TCNT1L;
#elif defined(TCNT0L)
    unsigned char value = TCNT0L;
#else
    unsigned char value = TCNT0;
#endif
    // Use Jenkin's one-at-a-time hash function to scatter the entropy a bit.
    // https://en.wikipedia.org/wiki/Jenkins_hash_function
    hash += value;
    hash += leftShift10(hash);
    hash ^= rightShift6(hash);
    ++outBits;
}
#endif // RNG_WATCHDOG
/** @endcond */
/**
 * \brief Constructs a new random number generator instance.
 *
 * This constructor must be followed by a call to begin() to
 * properly initialize the random number generator.
 *
 * \sa begin()
 */
RNGClass::RNGClass()
    : credits(0)
    , firstSave(1)
    , initialized(0)
    , trngPending(0)
    , timer(0)
    , timeout(3600000UL)    // 1 hour in milliseconds
    , count(0)
    , trngPosn(0)
{
}
/**
 * \brief Destroys this random number generator instance.
 */
RNGClass::~RNGClass()
{
#if defined(RNG_DUE_TRNG)
    // Disable the TRNG in the Arduino Due.
    REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
#endif
#if defined(RNG_WATCHDOG)
    // Disable interrupts and reset the watchdog.
    cli();
    wdt_reset();
    // Clear the "reset due to watchdog" flag.
    MCUSR &= ~(1 << WDRF);
    // Disable the watchdog.
    _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
    _WD_CONTROL_REG = 0;
    // Re-enable interrupts.  The watchdog should be stopped.
    sei();
#endif
    clean(block);
    clean(stream);
}
#if defined(RNG_DUE_TRNG)
// Find the flash memory of interest.  Allow for the possibility
// of other SAM-based Arduino variants in the future.
#if defined(IFLASH1_ADDR)
#define RNG_FLASH_ADDR      IFLASH1_ADDR
#define RNG_FLASH_SIZE      IFLASH1_SIZE
#define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
#define RNG_EFC             EFC1
#elif defined(IFLASH0_ADDR)
#define RNG_FLASH_ADDR      IFLASH0_ADDR
#define RNG_FLASH_SIZE      IFLASH0_SIZE
#define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
#define RNG_EFC             EFC0
#else
#define RNG_FLASH_ADDR      IFLASH_ADDR
#define RNG_FLASH_SIZE      IFLASH_SIZE
#define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
#define RNG_EFC             EFC
#endif
// Address of the flash page to use for saving the seed on the Due.
// All SAM variants have a page size of 256 bytes or greater so there is
// plenty of room for the 48 byte seed in the last page of flash memory.
#define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
#define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
// Stir in the unique identifier for the Arduino Due's CPU.
// This function must be in RAM because programs running out of
// flash memory are not allowed to access the unique identifier.
// Info from: http://forum.arduino.cc/index.php?topic=289190.0
__attribute__((section(".ramfunc")))
static void stirUniqueIdentifier(void)
{
    uint32_t id[4];
    // Start Read Unique Identifier.
    RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
    while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
        ;   // do nothing until FRDY falls.
    // Read the identifier.
    id[0] = *((const uint32_t *)RNG_FLASH_ADDR);
    id[1] = *((const uint32_t *)(RNG_FLASH_ADDR + 4));
    id[2] = *((const uint32_t *)(RNG_FLASH_ADDR + 8));
    id[3] = *((const uint32_t *)(RNG_FLASH_ADDR + 12));
    // Stop Read Unique Identifier.
    RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
    while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
        ;   // do nothing until FRDY rises.
    // Stir the unique identifier into the entropy pool.
    RNG.stir((uint8_t *)id, sizeof(id));
}
// Erases the flash page containing the seed and then writes the new seed.
// It is assumed the seed has already been loaded into the latch registers.
__attribute__((section(".ramfunc")))
static void eraseAndWriteSeed()
{
    // Execute the "Erase and Write Page" command.
    RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
    // Wait for the FRDY bit to be raised.
    while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
        ;   // do nothing until FRDY rises.
}
#endif
/**
 * \brief Initializes the random number generator.
 *
 * \param tag A string that is stirred into the random pool at startup;
 * usually this should be a value that is unique to the application and
 * version such as "MyApp 1.0" so that different applications do not
 * generate the same sequence of values upon first boot.
 *
 * This function should be followed by calls to addNoiseSource() to
 * register the application's noise sources.
 *
 * \sa addNoiseSource(), stir(), save()
 */
void RNGClass::begin(const char *tag)
{
    // Bail out if we have already done this.
    if (initialized)
        return;
    // Initialize the ChaCha20 input block from the saved seed.
    memcpy_P(block, tagRNG, sizeof(tagRNG));
    memcpy_P(block + 4, initRNG, sizeof(initRNG));
#if defined(RNG_EEPROM)
    int address = RNG_EEPROM_ADDRESS;
    eeprom_read_block(stream, (const void *)address, SEED_SIZE);
    if (crypto_crc8('S', stream, SEED_SIZE - 1) ==
            ((const uint8_t *)stream)[SEED_SIZE - 1]) {
        // We have a saved seed: XOR it with the initialization block.
        // Note: the CRC-8 value is included.  No point throwing it away.
        for (int posn = 0; posn < 12; ++posn)
            block[posn + 4] ^= stream[posn];
    }
#elif defined(RNG_DUE_TRNG)
    // Do we have a seed saved in the last page of flash memory on the Due?
    if (crypto_crc8('S', ((const uint32_t *)RNG_SEED_ADDR) + 1, SEED_SIZE)
            == ((const uint32_t *)RNG_SEED_ADDR)[0]) {
        // XOR the saved seed with the initialization block.
        for (int posn = 0; posn < 12; ++posn)
            block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1];
    }
    // If the device has just been reprogrammed, there will be no saved seed.
    // XOR the initialization block with some output from the CPU's TRNG
    // to permute the state in a first boot situation after reprogramming.
    pmc_enable_periph_clk(ID_TRNG);
    REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
    REG_TRNG_IDR = TRNG_IDR_DATRDY; // Disable interrupts - we will poll.
    mixTRNG();
#endif
#if defined(RNG_ESP_NVS)
    // Do we have a seed saved in ESP non-volatile storage (NVS)?
    nvs_handle handle = 0;
    if (nvs_open("rng", NVS_READONLY, &handle) == 0) {
        size_t len = 0;
        if (nvs_get_blob(handle, "seed", NULL, &len) == 0 && len == SEED_SIZE) {
            uint32_t seed[12];
            if (nvs_get_blob(handle, "seed", seed, &len) == 0) {
                for (int posn = 0; posn < 12; ++posn)
                    block[posn + 4] ^= seed[posn];
            }
            clean(seed);
        }
        nvs_close(handle);
    }
#endif
#if defined(RNG_WORD_TRNG)
    // Mix in some output from a word-based TRNG to initialize the state.
    mixTRNG();
#endif
    // No entropy credits for the saved seed.
    credits = 0;
    // Trigger an automatic save once the entropy credits max out.
    firstSave = 1;
    // Rekey the random number generator immediately.
    rekey();
    // Stir in the supplied tag data but don't credit any entropy to it.
    if (tag)
        stir((const uint8_t *)tag, strlen(tag));
#if defined(RNG_DUE_TRNG)
    // Stir in the unique identifier for the CPU so that different
    // devices will give different outputs even without seeding.
    stirUniqueIdentifier();
#elif defined(ESP8266)
    // ESP8266's have a 32-bit CPU chip ID and 32-bit flash chip ID
    // that we can use as a device unique identifier.
    uint32_t ids[2];
    ids[0] = ESP.getChipId();
    ids[1] = ESP.getFlashChipId();
    stir((const uint8_t *)ids, sizeof(ids));
#elif defined(ESP32)
    // ESP32's have a MAC address that can be used as a device identifier.
    uint64_t mac = ESP.getEfuseMac();
    stir((const uint8_t *)&mac, sizeof(mac));
#else
    // AVR devices don't have anything like a serial number so it is
    // difficult to make every device unique.  Use the compilation
    // time and date to provide a little randomness across applications
    // if not across devices running the same pre-compiled application.
    tag = __TIME__ __DATE__;
    stir((const uint8_t *)tag, strlen(tag));
#endif
#if defined(RNG_WATCHDOG)
    // Disable interrupts and reset the watchdog.
    cli();
    wdt_reset();
    // Clear the "reset due to watchdog" flag.
    MCUSR &= ~(1 << WDRF);
    // Enable the watchdog with the smallest duration (16ms)
    // and interrupt-only mode.
    _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
    _WD_CONTROL_REG = (1 << WDIE);
    // Re-enable interrupts.  The watchdog should be running.
    sei();
#endif
    // Re-save the seed to obliterate the previous value and to ensure
    // that if the system is reset without a call to save() that we won't
    // accidentally generate the same sequence of random data again.
    save();
    // The RNG has now been initialized.
    initialized = 1;
}
/**
 * \brief Adds a noise source to the random number generator.
 *
 * \param source The noise source to add, which will be polled regularly
 * by loop() to accumulate noise-based entropy from the source.
 *
 * RNG supports a maximum of four noise sources.  If the application needs
 * more than that then the application must poll the noise sources itself by
 * calling NoiseSource::stir() directly.
 *
 * \sa loop(), begin()
 */
void RNGClass::addNoiseSource(NoiseSource &source)
{
    #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
    if (count < MAX_NOISE_SOURCES) {
        noiseSources[count++] = &source;
        source.added();
    }
}
/**
 * \brief Sets the amount of time between automatic seed saves.
 *
 * \param minutes The number of minutes between automatic seed saves.
 *
 * The default time between automatic seed saves is 1 hour.
 *
 * This function is intended to help with EEPROM wear by slowing down how
 * often seed data is saved as noise is stirred into the random pool.
 * The exact period to use depends upon how long you intend to field
 * the device before replacing it.  For example, an EEPROM rated for
 * 100k erase/write cycles will last about 69 days saving once a minute
 * or 11 years saving once an hour.
 *
 * \sa save(), stir()
 */
void RNGClass::setAutoSaveTime(uint16_t minutes)
{
    if (!minutes)
        minutes = 1; // Just in case.
    timeout = ((uint32_t)minutes) * 60000U;
}
/**
 * \brief Generates random bytes into a caller-supplied buffer.
 *
 * \param data Points to the buffer to fill with random bytes.
 * \param len Number of bytes to generate.
 *
 * Calling this function will decrease the amount of entropy in the
 * random number pool by \a len * 8 bits.  If there isn't enough
 * entropy, then this function will still return \a len bytes of
 * random data generated from what entropy it does have.
 *
 * If the application requires a specific amount of entropy before
 * generating important values, the available() function can be
 * polled to determine when sufficient entropy is available.
 *
 * \sa available(), stir()
 */
void RNGClass::rand(uint8_t *data, size_t len)
{
    // Make sure that the RNG is initialized in case the application
    // forgot to call RNG.begin() at startup time.
    if (!initialized)
        begin(0);
    // Decrease the amount of entropy in the pool.
    if (len > (credits / 8u))
        credits = 0;
    else
        credits -= len * 8;
    // If we have pending TRNG data from the loop() function,
    // then force a stir on the state.  Otherwise mix in some
    // fresh data from the TRNG because it is possible that
    // the application forgot to call RNG.loop().
    if (trngPending) {
        stir(0, 0, 0);
        trngPending = 0;
        trngPosn = 0;
    } else {
        mixTRNG();
    }
    // Generate the random data.
    uint8_t count = 0;
    while (len > 0) {
        // 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.
        if (len < 64) {
            memcpy(data, stream, len);
            break;
        } else {
            memcpy(data, stream, 64);
            data += 64;
            len -= 64;
        }
    }
    // Force a rekey after every request.
    rekey();
}
/**
 * \brief Determine if there is sufficient entropy available for a
 * specific request size.
 *
 * \param len The number of bytes of random data that will be requested
 * via a call to rand().
 * \return Returns true if there is at least \a len * 8 bits of entropy
 * in the random number pool, or false if not.
 *
 * This function can be used by the application to wait for sufficient
 * entropy to become available from the system's noise sources before
 * generating important values.  For example:
 *
 * \code
 * bool haveKey = false;
 * byte key[32];
 *
 * void loop() {
 *     ...
 *
 *     if (!haveKey && RNG.available(sizeof(key))) {
 *         RNG.rand(key, sizeof(key));
 *         haveKey = true;
 *     }
 *
 *     ...
 * }
 * \endcode
 *
 * If \a len is larger than the maximum number of entropy credits supported
 * by the random number pool (384 bits, 48 bytes), then the maximum will be
 * used instead.  For example, asking if 512 bits (64 bytes) are available
 * will return true if in reality only 384 bits are available.  If this is a
 * problem for the application's security requirements, then large requests
 * for random data should be broken up into smaller chunks with the
 * application waiting for the entropy pool to refill between chunks.
 *
 * \sa rand()
 */
bool RNGClass::available(size_t len) const
{
    if (len >= (RNG_MAX_CREDITS / 8))
        return credits >= RNG_MAX_CREDITS;
    else
        return len <= (credits / 8u);
}
/**
 * \brief Stirs additional entropy data into the random pool.
 *
 * \param data Points to the additional data to be stirred in.
 * \param len Number of bytes to be stirred in.
 * \param credit The number of bits of entropy to credit for the
 * data that is stirred in.  Note that this is bits, not bytes.
 *
 * The maximum credit allowed is \a len * 8 bits, indicating that
 * every bit in the input \a data is good and random.  Practical noise
 * sources are rarely that good, so \a credit will usually be smaller.
 * For example, to credit 2 bits of entropy per byte, the function
 * would be called as follows:
 *
 * \code
 * RNG.stir(noise_data, noise_bytes, noise_bytes * 2);
 * \endcode
 *
 * If \a credit is zero, then the \a data will be stirred in but no
 * entropy credit is given.  This is useful for static values like
 * serial numbers and MAC addresses that are different between
 * devices but highly predictable.
 *
 * \sa loop()
 */
void RNGClass::stir(const uint8_t *data, size_t len, unsigned int credit)
{
    // Increase the entropy credit.
    if ((credit / 8) >= len && len)
        credit = len * 8;
    if ((RNG_MAX_CREDITS - credits) > credit)
        credits += credit;
    else
        credits = RNG_MAX_CREDITS;
    // Process the supplied input data.
    if (len > 0) {
        // XOR the data with the ChaCha input block in 48 byte
        // chunks and rekey the ChaCha cipher for each chunk to mix
        // the data in.  This should scatter any "true entropy" in
        // the input across the entire block.
        while (len > 0) {
            size_t templen = len;
            if (templen > 48)
                templen = 48;
            uint8_t *output = ((uint8_t *)block) + 16;
            len -= templen;
            while (templen > 0) {
                *output++ ^= *data++;
                --templen;
            }
            rekey();
        }
    } else {
        // There was no input data, so just force a rekey so we
        // get some mixing of the state even without new data.
        rekey();
    }
    // Save if this is the first time we have reached max entropy.
    // This provides some protection if the system is powered off before
    // the first auto-save timeout occurs.
    if (firstSave && credits >= RNG_MAX_CREDITS) {
        firstSave = 0;
        save();
    }
}
/**
 * \brief Saves the random seed to EEPROM.
 *
 * During system startup, noise sources typically won't have accumulated
 * much entropy.  But startup is usually the time when the system most
 * needs to generate random data for session keys, IV's, and the like.
 *
 * The purpose of this function is to pass some of the accumulated entropy
 * from one session to the next after a loss of power.  Thus, once the system
 * has been running for a while it will get progressively better at generating
 * random values and the accumulated entropy will not be completely lost.
 *
 * Normally it isn't necessary to call save() directly.  The loop() function
 * will automatically save the seed on a periodic basis (default of 1 hour).
 *
 * The seed that is saved is generated in such a way that it cannot be used
 * to predict random values that were generated previously or subsequently
 * in the current session.  So a compromise of the EEPROM contents of a
 * captured device should not result in compromise of random values
 * that have already been generated.  However, if power is lost and the
 * system restarted, then there will be a short period of time where the
 * random state will be predictable from the seed.  For this reason it is
 * very important to stir() in new noise data at startup.
 *
 * \sa loop(), stir()
 */
void RNGClass::save()
{
    // Generate random data from the current state and save
    // that as the seed.  Then force a rekey.
    ++(block[12]);
    ChaCha::hashCore(stream, block, RNG_ROUNDS);
#if defined(RNG_EEPROM)
    // We shorten the seed from 48 bytes to 47 to leave room for
    // the CRC-8 value.  We do this to align the data on an 8-byte
    // boundary in EERPOM.
    int address = RNG_EEPROM_ADDRESS;
    eeprom_write_block(stream, (void *)address, SEED_SIZE - 1);
    eeprom_write_byte((uint8_t *)(address + SEED_SIZE - 1),
                      crypto_crc8('S', stream, SEED_SIZE - 1));
#elif defined(RNG_DUE_TRNG)
    unsigned posn;
    ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8('S', stream, SEED_SIZE);
    for (posn = 0; posn < 12; ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
    for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
    eraseAndWriteSeed();
#elif defined(RNG_ESP_NVS)
    // Save the seed into ESP non-volatile storage (NVS).
    nvs_handle handle = 0;
    if (nvs_open("rng", NVS_READWRITE, &handle) == 0) {
        nvs_erase_all(handle);
        nvs_set_blob(handle, "seed", stream, SEED_SIZE);
        nvs_commit(handle);
        nvs_close(handle);
    }
#endif
    rekey();
    timer = millis();
}
/**
 * \brief Run periodic housekeeping tasks on the random number generator.
 *
 * This function must be called on a regular basis from the application's
 * main "loop()" function.
 */
void RNGClass::loop()
{
    // Stir in the entropy from all registered noise sources.
    for (uint8_t posn = 0; posn < count; ++posn)
        noiseSources[posn]->stir();
#if defined(RNG_DUE_TRNG)
    // If there is data available from the Arudino Due's TRNG, then XOR
    // it with the state block and increase the entropy credit.  We don't
    // call stir() yet because that will seriously slow down the system
    // given how fast the TRNG is.  Instead we save up the XOR'ed TRNG
    // data until the next rand() call and then hash it to generate the
    // desired output.
    //
    // The CPU documentation claims that the TRNG output is very good so
    // this should only make the pool more and more random as time goes on.
    // However there is a risk that the CPU manufacturer was pressured by
    // government or intelligence agencies to insert a back door that
    // generates predictable output.  Or the manufacturer was overly
    // optimistic about their TRNG design and it is actually flawed in a
    // way they don't realise.
    //
    // If you are concerned about such threats, then make sure to mix in
    // data from other noise sources.  By hashing together the TRNG with
    // the other noise data, rand() should produce unpredictable data even
    // if one of the sources is actually predictable.
    if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
        block[4 + trngPosn] ^= REG_TRNG_ODATA;
        if (++trngPosn >= 12)
            trngPosn = 0;
        if (credits < RNG_MAX_CREDITS) {
            // Credit 1 bit of entropy for the word.  The TRNG should be
            // better than this but it is so fast that we want to collect
            // up more data before passing it to the application.
            ++credits;
        }
        trngPending = 1;
    }
#elif defined(RNG_WORD_TRNG)
    // Read a word from the TRNG and XOR it into the state.
    block[4 + trngPosn] ^= RNG_WORD_TRNG_GET();
    if (++trngPosn >= 12)
        trngPosn = 0;
    if (credits < RNG_MAX_CREDITS) {
        // Credit 1 bit of entropy for the word.  The TRNG should be
        // better than this but it is so fast that we want to collect
        // up more data before passing it to the application.
        ++credits;
    }
    trngPending = 1;
#elif defined(RNG_WATCHDOG)
    // Read the 32 bit buffer from the WDT interrupt.
    cli();
    if (outBits >= 32) {
        uint32_t value = hash;
        hash = 0;
        outBits = 0;
        sei();
        // Final steps of the Jenkin's one-at-a-time hash function.
        // https://en.wikipedia.org/wiki/Jenkins_hash_function
        value += leftShift3(value);
        value ^= rightShift11(value);
        value += leftShift15(value);
        // Credit 1 bit of entropy for each byte of input.  It can take
        // between 30 and 40 seconds to accumulate 256 bits of credit.
        credits += 4;
        if (credits > RNG_MAX_CREDITS)
            credits = RNG_MAX_CREDITS;
        // XOR the word with the state.  Stir once we accumulate 48 bytes,
        // which happens about once every 6.4 seconds.
        block[4 + trngPosn] ^= value;
        if (++trngPosn >= 12) {
            trngPosn = 0;
            trngPending = 0;
            stir(0, 0, 0);
        } else {
            trngPending = 1;
        }
    } else {
        sei();
    }
#endif
    // Save the seed if the auto-save timer has expired.
    if ((millis() - timer) >= timeout)
        save();
}
/**
 * \brief Destroys the data in the random number pool and the saved seed
 * in EEPROM.
 *
 * This function attempts to throw away any data that could theoretically be
 * used to predict previous and future outputs of the random number generator
 * if the device is captured, sold, or otherwise compromised.
 *
 * After this function is called, begin() must be called again to
 * re-initialize the random number generator.
 *
 * \note The rand() and save() functions take some care to manage the
 * random number pool in a way that makes prediction of past outputs from a
 * captured state very difficult.  Future outputs may be predictable if
 * noise or other high-entropy data is not mixed in with stir() on a
 * regular basis.
 *
 * \sa begin()
 */
void RNGClass::destroy()
{
    clean(block);
    clean(stream);
#if defined(RNG_EEPROM)
    int address = RNG_EEPROM_ADDRESS;
    for (int posn = 0; posn < SEED_SIZE; ++posn)
        eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
#elif defined(RNG_DUE_TRNG)
    for (unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
        ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
    eraseAndWriteSeed();
#elif defined(RNG_ESP_NVS)
    nvs_handle handle = 0;
    if (nvs_open("rng", NVS_READWRITE, &handle) == 0) {
        nvs_erase_all(handle);
        nvs_commit(handle);
        nvs_close(handle);
    }
#endif
    initialized = 0;
}
/**
 * \brief Rekeys the random number generator.
 */
void RNGClass::rekey()
{
    // Rekey the cipher for the next request by generating a new block.
    // This is intended to make it difficult to wind the random number
    // backwards if the state is captured later.  The first 16 bytes of
    // "block" remain set to "tagRNG".
    ++(block[12]);
    ChaCha::hashCore(stream, block, RNG_ROUNDS);
    memcpy(block + 4, stream, 48);
    // Permute the high word of the counter using the system microsecond
    // counter to introduce a little bit of non-stir randomness for each
    // request.  Note: If random data is requested on a predictable schedule
    // then this may not help very much.  It is still necessary to stir in
    // high quality entropy data on a regular basis using stir().
    block[13] ^= micros();
}
/**
 * \brief Mix in fresh data from the TRNG when rand() is called.
 */
void RNGClass::mixTRNG()
{
#if defined(RNG_DUE_TRNG)
    // Mix in 12 words from the Due's TRNG.
    for (int posn = 0; posn < 12; ++posn) {
        // According to the documentation the TRNG should produce a new
        // 32-bit random value every 84 clock cycles.  If it still hasn't
        // produced a value after 200 iterations, then assume that the
        // TRNG is not producing output and stop.
        int counter;
        for (counter = 0; counter < 200; ++counter) {
            if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
                break;
        }
        if (counter >= 200)
            break;
        block[posn + 4] ^= REG_TRNG_ODATA;
    }
#elif defined(RNG_WORD_TRNG)
    // Read 12 words from the TRNG and XOR them into the state.
    for (uint8_t index = 4; index < 16; ++index)
        block[index] ^= RNG_WORD_TRNG_GET();
#elif defined(RNG_WATCHDOG)
    // Read the pending 32 bit buffer from the WDT interrupt and mix it in.
    cli();
    if (outBits >= 32) {
        uint32_t value = hash;
        hash = 0;
        outBits = 0;
        sei();
        // Final steps of the Jenkin's one-at-a-time hash function.
        // https://en.wikipedia.org/wiki/Jenkins_hash_function
        value += leftShift3(value);
        value ^= rightShift11(value);
        value += leftShift15(value);
        // XOR the word with the state.
        block[4] ^= value;
    } else {
        sei();
    }
#endif
}
src/modules/Crypto/RNG.h
New file
@@ -0,0 +1,74 @@
/*
 * 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.
 */
#ifndef CRYPTO_RNG_h
#define CRYPTO_RNG_h
#include <inttypes.h>
#include <stddef.h>
class NoiseSource;
class RNGClass
{
public:
    RNGClass();
    ~RNGClass();
    void begin(const char *tag);
    void addNoiseSource(NoiseSource &source);
    void setAutoSaveTime(uint16_t minutes);
    void rand(uint8_t *data, size_t len);
    bool available(size_t len) const;
    void stir(const uint8_t *data, size_t len, unsigned int credit = 0);
    void save();
    void loop();
    void destroy();
    static const int SEED_SIZE = 48;
private:
    uint32_t block[16];
    uint32_t stream[16];
    uint16_t credits : 13;
    uint16_t firstSave : 1;
    uint16_t initialized : 1;
    uint16_t trngPending : 1;
    unsigned long timer;
    unsigned long timeout;
    NoiseSource *noiseSources[4];
    uint8_t count;
    uint8_t trngPosn;
    void rekey();
    void mixTRNG();
};
extern RNGClass RNG;
#endif
src/modules/Crypto/SHA256.cpp
New file
@@ -0,0 +1,258 @@
/*
 * 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 "SHA256.h"
#include "Crypto.h"
#include "utility/RotateUtil.h"
#include "utility/EndianUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
 * \class SHA256 SHA256.h <SHA256.h>
 * \brief SHA-256 hash algorithm.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-2
 *
 * \sa SHA512, SHA3_256, BLAKE2s
 */
/**
 * \brief Constructs a SHA-256 hash object.
 */
SHA256::SHA256()
{
    reset();
}
/**
 * \brief Destroys this SHA-256 hash object after clearing
 * sensitive information.
 */
SHA256::~SHA256()
{
    clean(state);
}
size_t SHA256::hashSize() const
{
    return 32;
}
size_t SHA256::blockSize() const
{
    return 64;
}
void SHA256::reset()
{
    state.h[0] = 0x6a09e667;
    state.h[1] = 0xbb67ae85;
    state.h[2] = 0x3c6ef372;
    state.h[3] = 0xa54ff53a,
    state.h[4] = 0x510e527f;
    state.h[5] = 0x9b05688c;
    state.h[6] = 0x1f83d9ab;
    state.h[7] = 0x5be0cd19;
    state.chunkSize = 0;
    state.length = 0;
}
void SHA256::update(const void *data, size_t len)
{
    // Update the total length (in bits, not bytes).
    state.length += ((uint64_t)len) << 3;
    // Break the input up into 512-bit chunks and process each in turn.
    const uint8_t *d = (const uint8_t *)data;
    while (len > 0) {
        uint8_t size = 64 - state.chunkSize;
        if (size > len)
            size = len;
        memcpy(((uint8_t *)state.w) + state.chunkSize, d, size);
        state.chunkSize += size;
        len -= size;
        d += size;
        if (state.chunkSize == 64) {
            processChunk();
            state.chunkSize = 0;
        }
    }
}
void SHA256::finalize(void *hash, size_t len)
{
    // Pad the last chunk.  We may need two padding chunks if there
    // isn't enough room in the first for the padding and length.
    uint8_t *wbytes = (uint8_t *)state.w;
    if (state.chunkSize <= (64 - 9)) {
        wbytes[state.chunkSize] = 0x80;
        memset(wbytes + state.chunkSize + 1, 0x00, 64 - 8 - (state.chunkSize + 1));
        state.w[14] = htobe32((uint32_t)(state.length >> 32));
        state.w[15] = htobe32((uint32_t)state.length);
        processChunk();
    } else {
        wbytes[state.chunkSize] = 0x80;
        memset(wbytes + state.chunkSize + 1, 0x00, 64 - (state.chunkSize + 1));
        processChunk();
        memset(wbytes, 0x00, 64 - 8);
        state.w[14] = htobe32((uint32_t)(state.length >> 32));
        state.w[15] = htobe32((uint32_t)state.length);
        processChunk();
    }
    // Convert the result into big endian and return it.
    for (uint8_t posn = 0; posn < 8; ++posn)
        state.w[posn] = htobe32(state.h[posn]);
    // Copy the hash to the caller's return buffer.
    if (len > 32)
        len = 32;
    memcpy(hash, state.w, len);
}
void SHA256::clear()
{
    clean(state);
    reset();
}
void SHA256::resetHMAC(const void *key, size_t keyLen)
{
    formatHMACKey(state.w, key, keyLen, 0x36);
    state.length += 64 * 8;
    processChunk();
}
void SHA256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
    uint8_t temp[32];
    finalize(temp, sizeof(temp));
    formatHMACKey(state.w, key, keyLen, 0x5C);
    state.length += 64 * 8;
    processChunk();
    update(temp, sizeof(temp));
    finalize(hash, hashLen);
    clean(temp);
}
/**
 * \brief Processes a single 512-bit chunk with the core SHA-256 algorithm.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-2
 */
void SHA256::processChunk()
{
    // Round constants for SHA-256.
    static uint32_t const k[64] 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
    };
    // Convert the first 16 words from big endian to host byte order.
    uint8_t index;
    for (index = 0; index < 16; ++index)
        state.w[index] = be32toh(state.w[index]);
    // Initialise working variables to the current hash value.
    uint32_t a = state.h[0];
    uint32_t b = state.h[1];
    uint32_t c = state.h[2];
    uint32_t d = state.h[3];
    uint32_t e = state.h[4];
    uint32_t f = state.h[5];
    uint32_t g = state.h[6];
    uint32_t h = state.h[7];
    // Perform the first 16 rounds of the compression function main loop.
    uint32_t temp1, temp2;
    for (index = 0; index < 16; ++index) {
        temp1 = h + pgm_read_dword(k + index) + state.w[index] +
                (rightRotate6(e) ^ rightRotate11(e) ^ rightRotate25(e)) +
                ((e & f) ^ ((~e) & g));
        temp2 = (rightRotate2(a) ^ rightRotate13(a) ^ rightRotate22(a)) +
                ((a & b) ^ (a & c) ^ (b & c));
        h = g;
        g = f;
        f = e;
        e = d + temp1;
        d = c;
        c = b;
        b = a;
        a = temp1 + temp2;
    }
    // Perform the 48 remaining rounds.  We expand the first 16 words to
    // 64 in-place in the "w" array.  This saves 192 bytes of memory
    // that would have otherwise need to be allocated to the "w" array.
    for (; index < 64; ++index) {
        // Expand the next word.
        temp1 = state.w[(index - 15) & 0x0F];
        temp2 = state.w[(index - 2) & 0x0F];
        temp1 = state.w[index & 0x0F] =
            state.w[(index - 16) & 0x0F] + state.w[(index - 7) & 0x0F] +
                (rightRotate7(temp1) ^ rightRotate18(temp1) ^ (temp1 >> 3)) +
                (rightRotate17(temp2) ^ rightRotate19(temp2) ^ (temp2 >> 10));
        // Perform the round.
        temp1 = h + pgm_read_dword(k + index) + temp1 +
                (rightRotate6(e) ^ rightRotate11(e) ^ rightRotate25(e)) +
                ((e & f) ^ ((~e) & g));
        temp2 = (rightRotate2(a) ^ rightRotate13(a) ^ rightRotate22(a)) +
                ((a & b) ^ (a & c) ^ (b & c));
        h = g;
        g = f;
        f = e;
        e = d + temp1;
        d = c;
        c = b;
        b = a;
        a = temp1 + temp2;
    }
    // Add the compressed chunk to the current hash value.
    state.h[0] += a;
    state.h[1] += b;
    state.h[2] += c;
    state.h[3] += d;
    state.h[4] += e;
    state.h[5] += f;
    state.h[6] += g;
    state.h[7] += h;
    // Attempt to clean up the stack.
    a = b = c = d = e = f = g = h = temp1 = temp2 = 0;
}
src/modules/Crypto/SHA256.h
New file
@@ -0,0 +1,57 @@
/*
 * 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.
 */
#ifndef CRYPTO_SHA256_h
#define CRYPTO_SHA256_h
#include "Hash.h"
class SHA256 : public Hash
{
public:
    SHA256();
    virtual ~SHA256();
    size_t hashSize() const;
    size_t blockSize() const;
    void reset();
    void update(const void *data, size_t len);
    void finalize(void *hash, size_t len);
    void clear();
    void resetHMAC(const void *key, size_t keyLen);
    void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
private:
    struct {
        uint32_t h[8];
        uint32_t w[16];
        uint64_t length;
        uint8_t chunkSize;
    } state;
    void processChunk();
};
#endif
src/modules/Crypto/SHA3.cpp
New file
@@ -0,0 +1,168 @@
/*
 * 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 "SHA3.h"
#include "Crypto.h"
/**
 * \class SHA3_256 SHA3.h <SHA3.h>
 * \brief SHA3-256 hash algorithm.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHA3_512
 */
/**
 * \brief Constructs a new SHA3-256 hash object.
 */
SHA3_256::SHA3_256()
{
    core.setCapacity(512);
}
/**
 * \brief Destroys this hash object after clearing sensitive information.
 */
SHA3_256::~SHA3_256()
{
    // The destructor for the KeccakCore object will do most of the work.
}
size_t SHA3_256::hashSize() const
{
    return 32;
}
size_t SHA3_256::blockSize() const
{
    return core.blockSize();
}
void SHA3_256::reset()
{
    core.reset();
}
void SHA3_256::update(const void *data, size_t len)
{
    core.update(data, len);
}
void SHA3_256::finalize(void *hash, size_t len)
{
    // Pad the final block and then extract the hash value.
    core.pad(0x06);
    core.extract(hash, len);
}
void SHA3_256::clear()
{
    core.clear();
}
void SHA3_256::resetHMAC(const void *key, size_t keyLen)
{
    core.setHMACKey(key, keyLen, 0x36, 32);
}
void SHA3_256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
    uint8_t temp[32];
    finalize(temp, sizeof(temp));
    core.setHMACKey(key, keyLen, 0x5C, 32);
    core.update(temp, sizeof(temp));
    finalize(hash, hashLen);
    clean(temp);
}
/**
 * \class SHA3_512 SHA3.h <SHA3.h>
 * \brief SHA3-512 hash algorithm.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHA3_256
 */
/**
 * \brief Constructs a new SHA3-512 hash object.
 */
SHA3_512::SHA3_512()
{
    core.setCapacity(1024);
}
/**
 * \brief Destroys this hash object after clearing sensitive information.
 */
SHA3_512::~SHA3_512()
{
    // The destructor for the KeccakCore object will do most of the work.
}
size_t SHA3_512::hashSize() const
{
    return 64;
}
size_t SHA3_512::blockSize() const
{
    return core.blockSize();
}
void SHA3_512::reset()
{
    core.reset();
}
void SHA3_512::update(const void *data, size_t len)
{
    core.update(data, len);
}
void SHA3_512::finalize(void *hash, size_t len)
{
    // Pad the final block and then extract the hash value.
    core.pad(0x06);
    core.extract(hash, len);
}
void SHA3_512::clear()
{
    core.clear();
}
void SHA3_512::resetHMAC(const void *key, size_t keyLen)
{
    core.setHMACKey(key, keyLen, 0x36, 64);
}
void SHA3_512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
    uint8_t temp[64];
    finalize(temp, sizeof(temp));
    core.setHMACKey(key, keyLen, 0x5C, 64);
    core.update(temp, sizeof(temp));
    finalize(hash, hashLen);
    clean(temp);
}
src/modules/Crypto/SHA3.h
New file
@@ -0,0 +1,73 @@
/*
 * 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.
 */
#ifndef CRYPTO_SHA3_h
#define CRYPTO_SHA3_h
#include "KeccakCore.h"
#include "Hash.h"
class SHA3_256 : public Hash
{
public:
    SHA3_256();
    virtual ~SHA3_256();
    size_t hashSize() const;
    size_t blockSize() const;
    void reset();
    void update(const void *data, size_t len);
    void finalize(void *hash, size_t len);
    void clear();
    void resetHMAC(const void *key, size_t keyLen);
    void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
private:
    KeccakCore core;
};
class SHA3_512 : public Hash
{
public:
    SHA3_512();
    virtual ~SHA3_512();
    size_t hashSize() const;
    size_t blockSize() const;
    void reset();
    void update(const void *data, size_t len);
    void finalize(void *hash, size_t len);
    void clear();
    void resetHMAC(const void *key, size_t keyLen);
    void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
private:
    KeccakCore core;
};
#endif
src/modules/Crypto/SHA512.cpp
New file
@@ -0,0 +1,274 @@
/*
 * 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 "SHA512.h"
#include "Crypto.h"
#include "utility/RotateUtil.h"
#include "utility/EndianUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
 * \class SHA512 SHA512.h <SHA512.h>
 * \brief SHA-512 hash algorithm.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-2
 *
 * \sa SHA256, SHA3_512, BLAKE2b
 */
/**
 * \brief Constructs a SHA-512 hash object.
 */
SHA512::SHA512()
{
    reset();
}
/**
 * \brief Destroys this SHA-512 hash object after clearing
 * sensitive information.
 */
SHA512::~SHA512()
{
    clean(state);
}
size_t SHA512::hashSize() const
{
    return 64;
}
size_t SHA512::blockSize() const
{
    return 128;
}
void SHA512::reset()
{
    static uint64_t const hashStart[8] PROGMEM = {
        0x6A09E667F3BCC908ULL, 0xBB67AE8584CAA73BULL, 0x3C6EF372FE94F82BULL,
        0xA54FF53A5F1D36F1ULL, 0x510E527FADE682D1ULL, 0x9B05688C2B3E6C1FULL,
        0x1F83D9ABFB41BD6BULL, 0x5BE0CD19137E2179ULL
    };
    memcpy_P(state.h, hashStart, sizeof(hashStart));
    state.chunkSize = 0;
    state.lengthLow = 0;
    state.lengthHigh = 0;
}
void SHA512::update(const void *data, size_t len)
{
    // Update the total length in bits, not bytes.
    uint64_t temp = state.lengthLow;
    state.lengthLow += (((uint64_t)len) << 3);
    state.lengthHigh += (((uint64_t)len) >> 61);
    if (state.lengthLow < temp)
        ++state.lengthHigh;
    // Break the input up into 1024-bit chunks and process each in turn.
    const uint8_t *d = (const uint8_t *)data;
    while (len > 0) {
        uint8_t size = 128 - state.chunkSize;
        if (size > len)
            size = len;
        memcpy(((uint8_t *)state.w) + state.chunkSize, d, size);
        state.chunkSize += size;
        len -= size;
        d += size;
        if (state.chunkSize == 128) {
            processChunk();
            state.chunkSize = 0;
        }
    }
}
void SHA512::finalize(void *hash, size_t len)
{
    // Pad the last chunk.  We may need two padding chunks if there
    // isn't enough room in the first for the padding and length.
    uint8_t *wbytes = (uint8_t *)state.w;
    if (state.chunkSize <= (128 - 17)) {
        wbytes[state.chunkSize] = 0x80;
        memset(wbytes + state.chunkSize + 1, 0x00, 128 - 16 - (state.chunkSize + 1));
        state.w[14] = htobe64(state.lengthHigh);
        state.w[15] = htobe64(state.lengthLow);
        processChunk();
    } else {
        wbytes[state.chunkSize] = 0x80;
        memset(wbytes + state.chunkSize + 1, 0x00, 128 - (state.chunkSize + 1));
        processChunk();
        memset(wbytes, 0x00, 128 - 16);
        state.w[14] = htobe64(state.lengthHigh);
        state.w[15] = htobe64(state.lengthLow);
        processChunk();
    }
    // Convert the result into big endian and return it.
    for (uint8_t posn = 0; posn < 8; ++posn)
        state.w[posn] = htobe64(state.h[posn]);
    // Copy the hash to the caller's return buffer.
    if (len > 64)
        len = 64;
    memcpy(hash, state.w, len);
}
void SHA512::clear()
{
    clean(state);
    reset();
}
void SHA512::resetHMAC(const void *key, size_t keyLen)
{
    formatHMACKey(state.w, key, keyLen, 0x36);
    state.lengthLow += 128 * 8;
    processChunk();
}
void SHA512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
    uint8_t temp[64];
    finalize(temp, sizeof(temp));
    formatHMACKey(state.w, key, keyLen, 0x5C);
    state.lengthLow += 128 * 8;
    processChunk();
    update(temp, sizeof(temp));
    finalize(hash, hashLen);
    clean(temp);
}
/**
 * \brief Processes a single 1024-bit chunk with the core SHA-512 algorithm.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-2
 */
void SHA512::processChunk()
{
    // Round constants for SHA-512.
    static uint64_t const k[80] PROGMEM = {
        0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL,
        0xE9B5DBA58189DBBCULL, 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL,
        0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, 0xD807AA98A3030242ULL,
        0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL,
        0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL,
        0xC19BF174CF692694ULL, 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL,
        0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, 0x2DE92C6F592B0275ULL,
        0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL,
        0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL,
        0xBF597FC7BEEF0EE4ULL, 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL,
        0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, 0x27B70A8546D22FFCULL,
        0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL,
        0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL,
        0x92722C851482353BULL, 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL,
        0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, 0xD192E819D6EF5218ULL,
        0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL,
        0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL,
        0x34B0BCB5E19B48A8ULL, 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL,
        0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, 0x748F82EE5DEFB2FCULL,
        0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL,
        0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL,
        0xC67178F2E372532BULL, 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL,
        0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, 0x06F067AA72176FBAULL,
        0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL,
        0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL,
        0x431D67C49C100D4CULL, 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL,
        0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL
    };
    // Convert the first 16 words from big endian to host byte order.
    uint8_t index;
    for (index = 0; index < 16; ++index)
        state.w[index] = be64toh(state.w[index]);
    // Initialise working variables to the current hash value.
    uint64_t a = state.h[0];
    uint64_t b = state.h[1];
    uint64_t c = state.h[2];
    uint64_t d = state.h[3];
    uint64_t e = state.h[4];
    uint64_t f = state.h[5];
    uint64_t g = state.h[6];
    uint64_t h = state.h[7];
    // Perform the first 16 rounds of the compression function main loop.
    uint64_t temp1, temp2;
    for (index = 0; index < 16; ++index) {
        temp1 = h + pgm_read_qword(k + index) + state.w[index] +
                (rightRotate14_64(e) ^ rightRotate18_64(e) ^
                 rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
        temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
                 rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
        h = g;
        g = f;
        f = e;
        e = d + temp1;
        d = c;
        c = b;
        b = a;
        a = temp1 + temp2;
    }
    // Perform the 64 remaining rounds.  We expand the first 16 words to
    // 80 in-place in the "w" array.  This saves 512 bytes of memory
    // that would have otherwise need to be allocated to the "w" array.
    for (; index < 80; ++index) {
        // Expand the next word.
        temp1 = state.w[(index - 15) & 0x0F];
        temp2 = state.w[(index - 2) & 0x0F];
        temp1 = state.w[index & 0x0F] =
            state.w[(index - 16) & 0x0F] + state.w[(index - 7) & 0x0F] +
                (rightRotate1_64(temp1) ^ rightRotate8_64(temp1) ^
                 (temp1 >> 7)) +
                (rightRotate19_64(temp2) ^ rightRotate61_64(temp2) ^
                 (temp2 >> 6));
        // Perform the round.
        temp1 = h + pgm_read_qword(k + index) + temp1 +
                (rightRotate14_64(e) ^ rightRotate18_64(e) ^
                 rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
        temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
                 rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
        h = g;
        g = f;
        f = e;
        e = d + temp1;
        d = c;
        c = b;
        b = a;
        a = temp1 + temp2;
    }
    // Add the compressed chunk to the current hash value.
    state.h[0] += a;
    state.h[1] += b;
    state.h[2] += c;
    state.h[3] += d;
    state.h[4] += e;
    state.h[5] += f;
    state.h[6] += g;
    state.h[7] += h;
    // Attempt to clean up the stack.
    a = b = c = d = e = f = g = h = temp1 = temp2 = 0;
}
src/modules/Crypto/SHA512.h
New file
@@ -0,0 +1,62 @@
/*
 * 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.
 */
#ifndef CRYPTO_SHA512_h
#define CRYPTO_SHA512_h
#include "Hash.h"
class Ed25519;
class SHA512 : public Hash
{
public:
    SHA512();
    virtual ~SHA512();
    size_t hashSize() const;
    size_t blockSize() const;
    void reset();
    void update(const void *data, size_t len);
    void finalize(void *hash, size_t len);
    void clear();
    void resetHMAC(const void *key, size_t keyLen);
    void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
private:
    struct {
        uint64_t h[8];
        uint64_t w[16];
        uint64_t lengthLow;
        uint64_t lengthHigh;
        uint8_t chunkSize;
    } state;
    void processChunk();
    friend class Ed25519;
};
#endif
src/modules/Crypto/SHAKE.cpp
New file
@@ -0,0 +1,137 @@
/*
 * 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 "SHAKE.h"
/**
 * \class SHAKE SHAKE.h <SHAKE.h>
 * \brief Abstract base class for the SHAKE Extendable-Output Functions (XOFs).
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHAKE256, SHAKE128, SHA3_256
 */
/**
 * \brief Constructs a SHAKE object.
 *
 * \param capacity The capacity of the Keccak sponge function in bits which
 * should be a multiple of 64 and between 64 and 1536.
 */
SHAKE::SHAKE(size_t capacity)
    : finalized(false)
{
    core.setCapacity(capacity);
}
/**
 * \brief Destroys this SHAKE object after clearing all sensitive information.
 */
SHAKE::~SHAKE()
{
}
size_t SHAKE::blockSize() const
{
    return core.blockSize();
}
void SHAKE::reset()
{
    core.reset();
    finalized = false;
}
void SHAKE::update(const void *data, size_t len)
{
    if (finalized)
        reset();
    core.update(data, len);
}
void SHAKE::extend(uint8_t *data, size_t len)
{
    if (!finalized) {
        core.pad(0x1F);
        finalized = true;
    }
    core.extract(data, len);
}
void SHAKE::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
    if (!finalized) {
        core.pad(0x1F);
        finalized = true;
    }
    core.encrypt(output, input, len);
}
void SHAKE::clear()
{
    core.clear();
    finalized = false;
}
/**
 * \class SHAKE128 SHAKE.h <SHAKE.h>
 * \brief SHAKE Extendable-Output Function (XOF) with 128-bit security.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHAKE256, SHAKE, SHA3_256
 */
/**
 * \fn SHAKE128::SHAKE128()
 * \brief Constructs a SHAKE object with 128-bit security.
 */
/**
 * \brief Destroys this SHAKE128 object after clearing all sensitive
 * information.
 */
SHAKE128::~SHAKE128()
{
}
/**
 * \class SHAKE256 SHAKE.h <SHAKE.h>
 * \brief SHAKE Extendable-Output Function (XOF) with 256-bit security.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHAKE128, SHAKE, SHA3_256
 */
/**
 * \fn SHAKE256::SHAKE256()
 * \brief Constructs a SHAKE object with 256-bit security.
 */
/**
 * \brief Destroys this SHAKE256 object after clearing all sensitive
 * information.
 */
SHAKE256::~SHAKE256()
{
}
src/modules/Crypto/SHAKE.h
New file
@@ -0,0 +1,66 @@
/*
 * 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 CRYPTO_SHAKE_h
#define CRYPTO_SHAKE_h
#include "XOF.h"
#include "KeccakCore.h"
class SHAKE : public XOF
{
public:
    virtual ~SHAKE();
    size_t blockSize() const;
    void reset();
    void update(const void *data, size_t len);
    void extend(uint8_t *data, size_t len);
    void encrypt(uint8_t *output, const uint8_t *input, size_t len);
    void clear();
protected:
    SHAKE(size_t capacity);
private:
    KeccakCore core;
    bool finalized;
};
class SHAKE128 : public SHAKE
{
public:
    SHAKE128() : SHAKE(256) {}
    virtual ~SHAKE128();
};
class SHAKE256 : public SHAKE
{
public:
    SHAKE256() : SHAKE(512) {}
    virtual ~SHAKE256();
};
#endif
src/modules/Crypto/XOF.cpp
New file
@@ -0,0 +1,216 @@
/*
 * 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 "XOF.h"
/**
 * \class XOF XOF.h <XOF.h>
 * \brief Abstract base class for Extendable-Output Functions (XOFs).
 *
 * Extendable-Output Functions, or XOFs, are a new class of cryptographic
 * primitive that was defined by NIST during the SHA-3 standardization
 * process.  Essentially an XOF is a hash algorithm that has an
 * arbitrary-length output instead of a fixed-length digest.
 *
 * XOFs can be used for a variety of cryptographic tasks:
 *
 * \li Mask generation functions for RSA OAEP style padding.
 * \li Key derivation functions for expanding key seed material into
 * arbitrary amounts of keying material for a secure session.
 * \li Stream ciphers based on a key and IV.
 *
 * To use an XOF, it is first reset() and then data is added via multiple
 * calls to update():
 *
 * \code
 * SHAKE256 xof;
 * xof.reset();
 * xof.update(data1, sizeof(data1));
 * xof.update(data2, sizeof(data2));
 * ...
 * \endcode
 *
 * Once all input data has been added, the XOF switches into extend mode
 * to generate the arbitrary-length output data:
 *
 * \code
 * xof.extend(output1, sizeof(output1));
 * xof.extend(output2, sizeof(output2));
 * ...
 * \endcode
 *
 * Mask generation and key derivation is achieved as follows, where the
 * key is unique for each invocation:
 *
 * \code
 * SHAKE256 xof;
 * xof.reset();
 * xof.update(key, sizeof(key));
 * xof.extend(output, sizeof(output));
 * \endcode
 *
 * Stream ciphers can be constructed as follows, using the special
 * encrypt() function that XOR's the output of extend() with the
 * input plaintext to generate the output ciphertext (or alternatively
 * XOR's the output of extend() with the ciphertext to recover the
 * plaintext):
 *
 * \code
 * SHAKE256 xof;
 * xof.reset();
 * xof.update(key, sizeof(key));
 * xof.update(iv, sizeof(iv));
 * xof.encrypt(output1, input1, sizeof(input1));
 * xof.encrypt(output2, input2, sizeof(input2));
 * ...
 * \endcode
 *
 * If the key is reused, then the IV must be different for each session
 * or the encryption scheme can be easily broken.  It is better to
 * generate a new key and IV combination for every session.
 *
 * It may also be a good idea to include some tag information with the input
 * data to distinguish different uses of the XOF.  For example:
 *
 * \code
 * SHAKE256 xof;
 * xof.reset();
 * xof.update(key, sizeof(key));
 * xof.update(iv, sizeof(iv));
 * xof.update("MyCrypt", 7);
 * xof.encrypt(output, input, sizeof(input));
 * \endcode
 *
 * If the same key and IV was used with a different package, then it would
 * not generate the same output as "MyCrypt".
 *
 * NIST warns that XOFs should not be used in place of hash functions.
 * This is because of related outputs: if the same input is provided to
 * an XOF with different output lengths, then the shorter output will
 * be a prefix of the larger.  This breaks the expected collision-resistance
 * of regular hash functions.  There is typically no need to use an XOF
 * for hashing because NIST has already defined SHA3_256 and SHA3_512
 * for that purpose.
 *
 * Reference: http://en.wikipedia.org/wiki/SHA-3
 *
 * \sa SHAKE256, SHAKE128, SHA3_256
 */
/**
 * \brief Constructs a new XOF object.
 */
XOF::XOF()
{
}
/**
 * \brief Destroys this XOF object.
 *
 * \note Subclasses are responsible for clearing any sensitive data
 * that remains in the XOF object when it is destroyed.
 *
 * \sa clear()
 */
XOF::~XOF()
{
}
/**
 * \fn size_t XOF::blockSize() const
 * \brief Size of the internal block used by the XOF algorithm, in bytes.
 *
 * \sa update()
 */
/**
 * \fn void XOF::reset()
 * \brief Resets the XOF ready for a new session.
 *
 * \sa update(), extend(), encrypt()
 */
/**
 * \fn void XOF::update(const void *data, size_t len)
 * \brief Updates the XOF with more data.
 *
 * \param data Data to be hashed.
 * \param len Number of bytes of data to be added to the XOF.
 *
 * If extend() or encrypt() has already been called, then the behavior of
 * update() will be undefined.  Call reset() first to start a new session.
 *
 * \sa reset(), extend(), encrypt()
 */
/**
 * \fn void XOF::extend(uint8_t *data, size_t len)
 * \brief Generates extendable output from this XOF.
 *
 * \param data The data buffer to be filled.
 * \param len The number of bytes to write to \a data.
 *
 * \sa reset(), update(), encrypt()
 */
/**
 * \fn void XOF::encrypt(uint8_t *output, const uint8_t *input, size_t len)
 * \brief Encrypts an input buffer with extendable output from this XOF.
 *
 * \param output The output buffer to write to, which may be the same
 * buffer as \a input.  The \a output buffer must have at least as many
 * bytes as the \a input buffer.
 * \param input The input buffer to read from.
 * \param len The number of bytes to encrypt.
 *
 * This function is a convenience that generates data with extend() and
 * then XOR's it with the contents of \a input to generate the \a output.
 * This function can also be used to decrypt.
 *
 * The encrypt() function can be called multiple times with different
 * regions of the plaintext data.
 *
 * \sa reset(), update(), extend(), decrypt()
 */
/**
 * \fn void XOF::decrypt(uint8_t *output, const uint8_t *input, size_t len)
 * \brief Decrypts an input buffer with extendable output from this XOF.
 *
 * \param output The output buffer to write to, which may be the same
 * buffer as \a input.  The \a output buffer must have at least as many
 * bytes as the \a input buffer.
 * \param input The input buffer to read from.
 * \param len The number of bytes to encrypt.
 *
 * This is a convenience function that merely calls encrypt().
 *
 * \sa reset(), update(), extend(), encrypt()
 */
/**
 * \fn void XOF::clear()
 * \brief Clears the hash state, removing all sensitive data, and then
 * resets the XOF ready for a new session.
 *
 * \sa reset()
 */
src/modules/Crypto/XOF.h
New file
@@ -0,0 +1,51 @@
/*
 * 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 CRYPTO_XOF_h
#define CRYPTO_XOF_h
#include <inttypes.h>
#include <stddef.h>
class XOF
{
public:
    XOF();
    virtual ~XOF();
    virtual size_t blockSize() const = 0;
    virtual void reset() = 0;
    virtual void update(const void *data, size_t len) = 0;
    virtual void extend(uint8_t *data, size_t len) = 0;
    virtual void encrypt(uint8_t *output, const uint8_t *input, size_t len) = 0;
    inline void decrypt(uint8_t *output, const uint8_t *input, size_t len)
    {
        encrypt(output, input, len);
    }
    virtual void clear() = 0;
};
#endif
src/modules/Crypto/XTS.cpp
New file
@@ -0,0 +1,437 @@
/*
 * 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 "XTS.h"
#include "Crypto.h"
#include "GF128.h"
#include <string.h>
/**
 * \class XTSCommon XTS.h <XTS.h>
 * \brief Concrete base class to assist with implementing XTS mode for
 * 128-bit block ciphers.
 *
 * References: <a href="http://libeccio.di.unisa.it/Crypto14/Lab/p1619.pdf">IEEE Std. 1619-2007</a>, <a href="http://csrc.nist.gov/publications/nistpubs/800-38E/nist-sp-800-38E.pdf">NIST SP 800-38E</a>, a href="http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf">XEX</a>.
 *
 * \sa XTS, XTSSingleKey
 */
/**
 * \brief Constructs an XTS object with a default sector size of 512 bytes.
 */
XTSCommon::XTSCommon()
    : sectSize(512)
{
}
/**
 * \brief Clears all sensitive information and destroys this object.
 */
XTSCommon::~XTSCommon()
{
    clean(twk);
}
/**
 * \brief Gets the size of the key for XTS mode.
 *
 * The key size for XTS mode is twice the size of the underlying
 * block cipher key size.
 *
 * \sa setKey(), tweakSize()
 */
size_t XTSCommon::keySize() const
{
    return blockCipher1->keySize() * 2;
}
/**
 * \brief Gets the maximum supported size for the tweak.
 *
 * This function returns 16, which indicates that any tweak up to 16 bytes
 * in size can be specified via setTweak().
 */
size_t XTSCommon::tweakSize() const
{
    return 16;
}
/**
 * \fn size_t XTSCommon::sectorSize() const
 * \brief Gets the size of sectors encrypted or decrypted by this class.
 *
 * The default value is 512 bytes.
 *
 * \sa setSectorSize()
 */
/**
 * \brief Sets the size of sectors encrypted or decrypted by this class.
 *
 * \param size The sector size in bytes, which must be greater than or
 * equal to 16.
 *
 * \return Returns false if \a size is less than 16.
 *
 * \sa sectorSize(), encryptSector()
 */
bool XTSCommon::setSectorSize(size_t size)
{
    if (size < 16)
        return false;
    sectSize = size;
    return true;
}
/**
 * \brief Sets the key to use for XTS mode.
 *
 * \param key Points to the key.
 * \param len The size of the key in bytes which must be twice the
 * size of the underlying block cipher's key size.
 *
 * \return Returns true if the key was set or false if \a len was incorrect.
 *
 * This function should be followed by a call to setTweak() to specify
 * the sector-specific tweak.
 *
 * \sa keySize(), setTweak(), encryptSector()
 */
bool XTSCommon::setKey(const uint8_t *key, size_t len)
{
    if (!blockCipher1->setKey(key, len / 2))
        return false;
    return blockCipher2->setKey(key + len / 2, len - (len / 2));
}
/**
 * \brief Sets the tweak value for the current sector to encrypt or decrypt.
 *
 * \param tweak Points to the tweak.
 * \param len The length of the tweak which must be less than or equal to 16.
 *
 * \return Returns true if the tweak was set or false if \a len was incorrect.
 *
 * If \a len is less than 16, then the \a tweak will be zero-padded to
 * 16 bytes.
 *
 * The \a tweak is encrypted with the second half of the XTS key to generate
 * the actual tweak value for the sector.
 *
 * \sa tweakSize(), setKey(), encryptSector()
 */
bool XTSCommon::setTweak(const uint8_t *tweak, size_t len)
{
    if (len > 16)
        return false;
    memcpy(twk, tweak, len);
    memset(((uint8_t *)twk) + len, 0, 16 - len);
    blockCipher2->encryptBlock((uint8_t *)twk, (uint8_t *)twk);
    return true;
}
#define xorTweak(output, input, tweak) \
    do { \
        for (uint8_t i = 0; i < 16; ++i) \
            (output)[i] = (input)[i] ^ ((const uint8_t *)(tweak))[i]; \
    } while (0)
/**
 * \brief Encrypts an entire sector of data.
 *
 * \param output The output buffer to write the ciphertext to, which can
 * be the same as \a input.
 * \param input The input buffer to read the plaintext from.
 *
 * The \a input and \a output buffers must be at least sectorSize()
 * bytes in length.
 *
 * \sa decryptSector(), setKey(), setTweak()
 */
void XTSCommon::encryptSector(uint8_t *output, const uint8_t *input)
{
    size_t sectLast = sectSize & ~15;
    size_t posn = 0;
    uint32_t t[4];
    memcpy(t, twk, sizeof(t));
    while (posn < sectLast) {
        // Process all complete 16-byte blocks.
        xorTweak(output, input, t);
        blockCipher1->encryptBlock(output, output);
        xorTweak(output, output, t);
        GF128::dblXTS(t);
        input += 16;
        output += 16;
        posn += 16;
    }
    if (posn < sectSize) {
        // Perform ciphertext stealing on the final partial block.
        uint8_t leftOver = sectSize - posn;
        output -= 16;
        while (leftOver > 0) {
            // Swap the left-over bytes in the last two blocks.
            --leftOver;
            uint8_t temp = input[leftOver];
            output[leftOver + 16] = output[leftOver];
            output[leftOver] = temp;
        }
        xorTweak(output, output, t);
        blockCipher1->encryptBlock(output, output);
        xorTweak(output, output, t);
    }
}
/**
 * \brief Decrypts an entire sector of data.
 *
 * \param output The output buffer to write the plaintext to, which can
 * be the same as \a input.
 * \param input The input buffer to read the ciphertext from.
 *
 * The \a input and \a output buffers must be at least sectorSize()
 * bytes in length.
 *
 * \sa encryptSector(), setKey(), setTweak()
 */
void XTSCommon::decryptSector(uint8_t *output, const uint8_t *input)
{
    size_t sectLast = sectSize & ~15;
    size_t posn = 0;
    uint32_t t[4];
    memcpy(t, twk, sizeof(t));
    if (sectLast != sectSize)
        sectLast -= 16;
    while (posn < sectLast) {
        // Process all complete 16-byte blocks.
        xorTweak(output, input, t);
        blockCipher1->decryptBlock(output, output);
        xorTweak(output, output, t);
        GF128::dblXTS(t);
        input += 16;
        output += 16;
        posn += 16;
    }
    if (posn < sectSize) {
        // Perform ciphertext stealing on the final two blocks.
        uint8_t leftOver = sectSize - 16 - posn;
        uint32_t u[4];
        // Decrypt the second-last block of ciphertext to recover
        // the last partial block of plaintext.  We need to use
        // dblXTS(t) as the tweak for this block.  Save the current
        // tweak in "u" for use later.
        memcpy(u, t, sizeof(t));
        GF128::dblXTS(t);
        xorTweak(output, input, t);
        blockCipher1->decryptBlock(output, output);
        xorTweak(output, output, t);
        // Swap the left-over bytes in the last two blocks.
        while (leftOver > 0) {
            --leftOver;
            uint8_t temp = input[leftOver + 16];
            output[leftOver + 16] = output[leftOver];
            output[leftOver] = temp;
        }
        // Decrypt the second-last block using the second-last tweak.
        xorTweak(output, output, u);
        blockCipher1->decryptBlock(output, output);
        xorTweak(output, output, u);
    }
}
/**
 * \brief Clears all security-sensitive state from this XTS object.
 */
void XTSCommon::clear()
{
    clean(twk);
    blockCipher1->clear();
    blockCipher2->clear();
}
/**
 * \fn void XTSCommon::setBlockCiphers(BlockCipher *cipher1, BlockCipher *cipher2)
 * \brief Sets the two block ciphers to use for XTS mode.
 *
 * \param cipher1 Points to the first block cipher object, which must be
 * capable of both encryption and decryption.
 * \param cipher2 Points to the second block cipher object, which must be
 * capable of both encryption but does not need to be capable of decryption.
 *
 * Both block ciphers must have a 128-bit block size.
 */
/**
 * \class XTSSingleKeyCommon XTS.h <XTS.h>
 * \brief Concrete base class to assist with implementing single-key XTS
 * mode for 128-bit block ciphers.
 *
 * References: <a href="http://libeccio.di.unisa.it/Crypto14/Lab/p1619.pdf">IEEE Std. 1619-2007</a>, <a href="http://csrc.nist.gov/publications/nistpubs/800-38E/nist-sp-800-38E.pdf">NIST SP 800-38E</a>, a href="http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf">XEX</a>.
 *
 * \sa XTSSingleKey, XTSCommon
 */
/**
 * \fn XTSSingleKeyCommon::XTSSingleKeyCommon()
 * \brief Constructs an XTS object with a default sector size of 512 bytes.
 */
/**
 * \brief Clears all sensitive information and destroys this object.
 */
XTSSingleKeyCommon::~XTSSingleKeyCommon()
{
}
/**
 * \brief Gets the size of the key for single-pkey XTS mode.
 *
 * The key size for single-key XTS mode is the same as the key size
 * for the underlying block cipher.
 *
 * \sa setKey(), tweakSize()
 */
size_t XTSSingleKeyCommon::keySize() const
{
    return blockCipher1->keySize();
}
/**
 * \brief Sets the key to use for single-keyh XTS mode.
 *
 * \param key Points to the key.
 * \param len The size of the key in bytes which must be same as the
 * size of the underlying block cipher.
 *
 * \return Returns true if the key was set or false if \a len was incorrect.
 *
 * This function should be followed by a call to setTweak() to specify
 * the sector-specific tweak.
 *
 * \sa keySize(), setTweak(), encryptSector()
 */
bool XTSSingleKeyCommon::setKey(const uint8_t *key, size_t len)
{
    return blockCipher1->setKey(key, len);
}
/**
 * \class XTS XTS.h <XTS.h>
 * \brief Implementation of the XTS mode for 128-bit block ciphers.
 *
 * XTS mode implements the XEX tweakable block cipher mode with ciphertext
 * stealing for data that isn't a multiple of the 128-bit block size.
 *
 * XTS was designed for use in disk encryption where a large number of
 * equal-sized "sectors" need to be encrypted in a way that information
 * from one sector cannot be used to decrypt the other sectors.  The mode
 * combines the key with a sector-specific "tweak" which is usually
 * based on the sector number.
 *
 * Some Arduino systems have SD cards, but typically embedded systems
 * do not have disk drives.  However, XTS can still be useful on
 * Arduino systems with lots of EEPROM or flash memory.  If the application
 * needs to store critical security parameters like private keys then
 * XTS can be used to encrypt non-volatile memory to protect the parameters.
 *
 * The following example encrypts a sector using XTS mode:
 *
 * \code
 * XTS<AES256> xts;
 * xts.setSectorSize(520);
 * xts.setKey(key, 64); // Twice the AES256 key size.
 * xts.setTweak(sectorNumber, sizeof(sectorNumber));
 * xts.encryptSector(output, input);
 * \endcode
 *
 * XTS keys are twice the size of the underlying block cipher
 * (AES256 in the above example).  The XTS key is divided into two halves.
 * The first half is used to encrypt the plaintext and the second half
 * is used to encrypt the sector-specific tweak.  The same key can be
 * used for both, in which case XTS is equivalent to the original
 * XEX design upon which XTS was based.  The companion XTSSingleKey class
 * can be used for single-key scenarios.
 *
 * The template parameter must be a concrete subclass of BlockCipher
 * indicating the specific block cipher to use.  The example above uses
 * AES256 as the underlying cipher.
 *
 * It is also possible to specify two different block ciphers, as long as
 * they have the same key size.  Because the second half of the key is only
 * used to encrypt tweaks and never decrypt, a reduced block cipher
 * implementation like SpeckTiny that only supports encryption can be
 * used for the second block cipher:
 *
 * \code
 * XTS<SpeckSmall, SpeckTiny> xts;
 * \endcode
 *
 * This might save some memory that would otherwise be needed for the
 * decryption key schedule of the second block cipher.  XTSSingleKey provides
 * another method to save memory.
 *
 * References: <a href="http://libeccio.di.unisa.it/Crypto14/Lab/p1619.pdf">IEEE Std. 1619-2007</a>, <a href="http://csrc.nist.gov/publications/nistpubs/800-38E/nist-sp-800-38E.pdf">NIST SP 800-38E</a>, a href="http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf">XEX</a>.
 *
 * \sa XTSSingleKey, XTSCommon
 */
/**
 * \fn XTS::XTS()
 * \brief Constructs an object for encrypting sectors in XTS mode.
 *
 * This constructor should be followed by a call to setSectorSize().
 * The default sector size is 512 bytes.
 */
/**
 * \fn XTS::~XTS()
 * \brief Clears all sensitive information and destroys this object.
 */
/**
 * \class XTSSingleKey XTS.h <XTS.h>
 * \brief Implementation of the single-key XTS mode for 128-bit block ciphers.
 *
 * XTS mode normally uses two keys to encrypt plaintext and the
 * sector-specific tweak values.  This class uses the same key for
 * both purposes, which can help save memory.
 *
 * References: <a href="http://libeccio.di.unisa.it/Crypto14/Lab/p1619.pdf">IEEE Std. 1619-2007</a>, <a href="http://csrc.nist.gov/publications/nistpubs/800-38E/nist-sp-800-38E.pdf">NIST SP 800-38E</a>, a href="http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf">XEX</a>.
 *
 * \sa XTS, XTSSingleKeyCommon
 */
/**
 * \fn XTSSingleKey::XTSSingleKey()
 * \brief Constructs an object for encrypting sectors in XTS mode
 * with a single key instead of two split keys.
 *
 * This constructor should be followed by a call to setSectorSize().
 * The default sector size is 512 bytes.
 */
/**
 * \fn XTSSingleKey::~XTSSingleKey()
 * \brief Clears all sensitive information and destroys this object.
 */
src/modules/Crypto/XTS.h
New file
@@ -0,0 +1,101 @@
/*
 * 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 CRYPTO_XTS_h
#define CRYPTO_XTS_h
#include "BlockCipher.h"
class XTSSingleKeyCommon;
class XTSCommon
{
public:
    virtual ~XTSCommon();
    virtual size_t keySize() const;
    size_t tweakSize() const;
    size_t sectorSize() const { return sectSize; }
    bool setSectorSize(size_t size);
    virtual bool setKey(const uint8_t *key, size_t len);
    bool setTweak(const uint8_t *tweak, size_t len);
    void encryptSector(uint8_t *output, const uint8_t *input);
    void decryptSector(uint8_t *output, const uint8_t *input);
    void clear();
protected:
    XTSCommon();
    void setBlockCiphers(BlockCipher *cipher1, BlockCipher *cipher2)
    {
        blockCipher1 = cipher1;
        blockCipher2 = cipher2;
    }
private:
    BlockCipher *blockCipher1;
    BlockCipher *blockCipher2;
    uint32_t twk[4];
    size_t sectSize;
    friend class XTSSingleKeyCommon;
};
class XTSSingleKeyCommon : public XTSCommon
{
public:
    virtual ~XTSSingleKeyCommon();
    size_t keySize() const;
    bool setKey(const uint8_t *key, size_t len);
protected:
    XTSSingleKeyCommon() : XTSCommon() {}
};
template <typename T1, typename T2 = T1>
class XTS : public XTSCommon
{
public:
    XTS() { setBlockCiphers(&cipher1, &cipher2); }
    ~XTS() {}
private:
    T1 cipher1;
    T2 cipher2;
};
template <typename T>
class XTSSingleKey : public XTSSingleKeyCommon
{
public:
    XTSSingleKey() { setBlockCiphers(&cipher, &cipher); }
    ~XTSSingleKey() {}
private:
    T cipher;
};
#endif
src/modules/Crypto/examples/TestAES/TestAES.ino
New file
@@ -0,0 +1,175 @@
/*
 * 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.
 */
/*
This example runs tests on the AES implementation to verify correct behaviour.
*/
#include <Crypto.h>
#include <AES.h>
#include <string.h>
struct TestVector
{
    const char *name;
    byte key[32];
    byte plaintext[16];
    byte ciphertext[16];
};
// Define the ECB test vectors from the FIPS specification.
static TestVector const testVectorAES128 = {
    .name        = "AES-128-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30,
                    0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A}
};
static TestVector const testVectorAES192 = {
    .name        = "AES-192-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0xDD, 0xA9, 0x7C, 0xA4, 0x86, 0x4C, 0xDF, 0xE0,
                    0x6E, 0xAF, 0x70, 0xA0, 0xEC, 0x0D, 0x71, 0x91}
};
static TestVector const testVectorAES256 = {
    .name        = "AES-256-ECB",
    .key         = {0x00, 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
                    0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
};
AES128 aes128;
AES192 aes192;
AES256 aes256;
byte buffer[16];
void testCipher(BlockCipher *cipher, const struct TestVector *test)
{
    crypto_feed_watchdog();
    Serial.print(test->name);
    Serial.print(" Encryption ... ");
    cipher->setKey(test->key, cipher->keySize());
    cipher->encryptBlock(buffer, test->plaintext);
    if (memcmp(buffer, test->ciphertext, 16) == 0)
        Serial.println("Passed");
    else
        Serial.println("Failed");
    Serial.print(test->name);
    Serial.print(" Decryption ... ");
    cipher->decryptBlock(buffer, test->ciphertext);
    if (memcmp(buffer, test->plaintext, 16) == 0)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfCipher(BlockCipher *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    crypto_feed_watchdog();
    Serial.print(test->name);
    Serial.print(" Set Key ... ");
    start = micros();
    for (count = 0; count < 10000; ++count) {
        cipher->setKey(test->key, cipher->keySize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 10000.0);
    Serial.print("us per operation, ");
    Serial.print((10000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
    Serial.print(test->name);
    Serial.print(" Encrypt ... ");
    start = micros();
    for (count = 0; count < 5000; ++count) {
        cipher->encryptBlock(buffer, buffer);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (5000.0 * 16.0));
    Serial.print("us per byte, ");
    Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
    Serial.print(test->name);
    Serial.print(" Decrypt ... ");
    start = micros();
    for (count = 0; count < 5000; ++count) {
        cipher->decryptBlock(buffer, buffer);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (5000.0 * 16.0));
    Serial.print("us per byte, ");
    Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
    Serial.println();
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.println("State Sizes:");
    Serial.print("AES128 ... ");
    Serial.println(sizeof(AES128));
    Serial.print("AES192 ... ");
    Serial.println(sizeof(AES192));
    Serial.print("AES256 ... ");
    Serial.println(sizeof(AES256));
    Serial.println();
    Serial.println("Test Vectors:");
    testCipher(&aes128, &testVectorAES128);
    testCipher(&aes192, &testVectorAES192);
    testCipher(&aes256, &testVectorAES256);
    Serial.println();
    Serial.println("Performance Tests:");
    perfCipher(&aes128, &testVectorAES128);
    perfCipher(&aes192, &testVectorAES192);
    perfCipher(&aes256, &testVectorAES256);
}
void loop()
{
}
src/modules/Crypto/examples/TestAESSmall/TestAESSmall.ino
New file
@@ -0,0 +1,170 @@
/*
 * 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.
 */
/*
This example runs tests on the small AES implementation to verify behaviour.
*/
#include <Crypto.h>
#include <AES.h>
#include <string.h>
struct TestVector
{
    const char *name;
    byte key[32];
    byte plaintext[16];
    byte ciphertext[16];
};
// Define the ECB test vectors from the FIPS specification.
static TestVector const testVectorAES128 = {
    .name        = "AES-128-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30,
                    0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A}
};
static TestVector const testVectorAES192 = {
    .name        = "AES-192-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0xDD, 0xA9, 0x7C, 0xA4, 0x86, 0x4C, 0xDF, 0xE0,
                    0x6E, 0xAF, 0x70, 0xA0, 0xEC, 0x0D, 0x71, 0x91}
};
static TestVector const testVectorAES256 = {
    .name        = "AES-256-ECB",
    .key         = {0x00, 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
                    0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
};
AESSmall128 aes128;
AESSmall256 aes256;
byte buffer[16];
void testCipher(BlockCipher *cipher, const struct TestVector *test)
{
    crypto_feed_watchdog();
    Serial.print(test->name);
    Serial.print(" Encryption ... ");
    cipher->setKey(test->key, cipher->keySize());
    cipher->encryptBlock(buffer, test->plaintext);
    if (memcmp(buffer, test->ciphertext, 16) == 0)
        Serial.println("Passed");
    else
        Serial.println("Failed");
    Serial.print(test->name);
    Serial.print(" Decryption ... ");
    cipher->decryptBlock(buffer, test->ciphertext);
    if (memcmp(buffer, test->plaintext, 16) == 0)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfCipher(BlockCipher *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    crypto_feed_watchdog();
    Serial.print(test->name);
    Serial.print(" Set Key ... ");
    start = micros();
    for (count = 0; count < 10000; ++count) {
        cipher->setKey(test->key, cipher->keySize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 10000.0);
    Serial.print("us per operation, ");
    Serial.print((10000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
    Serial.print(test->name);
    Serial.print(" Encrypt ... ");
    start = micros();
    for (count = 0; count < 5000; ++count) {
        cipher->encryptBlock(buffer, buffer);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (5000.0 * 16.0));
    Serial.print("us per byte, ");
    Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
    Serial.print(test->name);
    Serial.print(" Decrypt ... ");
    start = micros();
    for (count = 0; count < 5000; ++count) {
        cipher->decryptBlock(buffer, buffer);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (5000.0 * 16.0));
    Serial.print("us per byte, ");
    Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
    Serial.println();
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.println("State Sizes:");
    Serial.print("AESSmall128 ... ");
    Serial.println(sizeof(AESSmall128));
    Serial.print("AESSmall256 ... ");
    Serial.println(sizeof(AESSmall256));
    Serial.println();
    Serial.println("Test Vectors:");
    testCipher(&aes128, &testVectorAES128);
    testCipher(&aes256, &testVectorAES256);
    Serial.println();
    Serial.println("Performance Tests:");
    perfCipher(&aes128, &testVectorAES128);
    perfCipher(&aes256, &testVectorAES256);
}
void loop()
{
}
src/modules/Crypto/examples/TestAESTiny/TestAESTiny.ino
New file
@@ -0,0 +1,150 @@
/*
 * 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.
 */
/*
This example runs tests on the tiny AES implementation to verify behaviour.
*/
#include <Crypto.h>
#include <AES.h>
#include <string.h>
struct TestVector
{
    const char *name;
    byte key[32];
    byte plaintext[16];
    byte ciphertext[16];
};
// Define the ECB test vectors from the FIPS specification.
static TestVector const testVectorAES128 = {
    .name        = "AES-128-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30,
                    0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A}
};
static TestVector const testVectorAES192 = {
    .name        = "AES-192-ECB",
    .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0xDD, 0xA9, 0x7C, 0xA4, 0x86, 0x4C, 0xDF, 0xE0,
                    0x6E, 0xAF, 0x70, 0xA0, 0xEC, 0x0D, 0x71, 0x91}
};
static TestVector const testVectorAES256 = {
    .name        = "AES-256-ECB",
    .key         = {0x00, 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
    .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                    0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    .ciphertext  = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
                    0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
};
AESTiny128 aes128;
AESTiny256 aes256;
byte buffer[16];
void testCipher(BlockCipher *cipher, const struct TestVector *test)
{
    crypto_feed_watchdog();
    Serial.print(test->name);
    Serial.print(" Encryption ... ");
    cipher->setKey(test->key, cipher->keySize());
    cipher->encryptBlock(buffer, test->plaintext);
    if (memcmp(buffer, test->ciphertext, 16) == 0)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfCipher(BlockCipher *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    crypto_feed_watchdog();
    Serial.print(test->name);
    Serial.print(" Set Key ... ");
    start = micros();
    for (count = 0; count < 10000; ++count) {
        cipher->setKey(test->key, cipher->keySize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 10000.0);
    Serial.print("us per operation, ");
    Serial.print((10000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
    Serial.print(test->name);
    Serial.print(" Encrypt ... ");
    start = micros();
    for (count = 0; count < 5000; ++count) {
        cipher->encryptBlock(buffer, buffer);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (5000.0 * 16.0));
    Serial.print("us per byte, ");
    Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
    Serial.println();
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.println("State Sizes:");
    Serial.print("AESTiny128 ... ");
    Serial.println(sizeof(AESTiny128));
    Serial.print("AESTiny256 ... ");
    Serial.println(sizeof(AESTiny256));
    Serial.println();
    Serial.println("Test Vectors:");
    testCipher(&aes128, &testVectorAES128);
    testCipher(&aes256, &testVectorAES256);
    Serial.println();
    Serial.println("Performance Tests:");
    perfCipher(&aes128, &testVectorAES128);
    perfCipher(&aes256, &testVectorAES256);
}
void loop()
{
}
src/modules/Crypto/examples/TestBLAKE2b/TestBLAKE2b.ino
New file
@@ -0,0 +1,410 @@
/*
 * 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.
 */
/*
This example runs tests on the BLAKE2b implementation to verify correct behaviour.
*/
#include <Crypto.h>
#include <BLAKE2b.h>
#include <string.h>
#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#define HASH_SIZE 64
#define BLOCK_SIZE 128
struct TestHashVector
{
    const char *name;
    const char *data;
    uint8_t hash[HASH_SIZE];
};
// Test vectors generated with the reference implementation of BLAKE2b.
static TestHashVector const testVectorBLAKE2b_1 PROGMEM = {
    "BLAKE2b #1",
    "",
    {0x78, 0x6a, 0x02, 0xf7, 0x42, 0x01, 0x59, 0x03,
     0xc6, 0xc6, 0xfd, 0x85, 0x25, 0x52, 0xd2, 0x72,
     0x91, 0x2f, 0x47, 0x40, 0xe1, 0x58, 0x47, 0x61,
     0x8a, 0x86, 0xe2, 0x17, 0xf7, 0x1f, 0x54, 0x19,
     0xd2, 0x5e, 0x10, 0x31, 0xaf, 0xee, 0x58, 0x53,
     0x13, 0x89, 0x64, 0x44, 0x93, 0x4e, 0xb0, 0x4b,
     0x90, 0x3a, 0x68, 0x5b, 0x14, 0x48, 0xb7, 0x55,
     0xd5, 0x6f, 0x70, 0x1a, 0xfe, 0x9b, 0xe2, 0xce}
};
static TestHashVector const testVectorBLAKE2b_2 PROGMEM = {
    "BLAKE2b #2",
    "abc",
    {0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d,
     0x6a, 0x27, 0x97, 0xb6, 0x9f, 0x12, 0xf6, 0xe9,
     0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a, 0xc4, 0xb7,
     0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1,
     0x7d, 0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d,
     0xc2, 0x52, 0xd5, 0xde, 0x45, 0x33, 0xcc, 0x95,
     0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92, 0x5a,
     0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23}
};
static TestHashVector const testVectorBLAKE2b_3 PROGMEM = {
    "BLAKE2b #3",
    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
    {0x72, 0x85, 0xff, 0x3e, 0x8b, 0xd7, 0x68, 0xd6,
     0x9b, 0xe6, 0x2b, 0x3b, 0xf1, 0x87, 0x65, 0xa3,
     0x25, 0x91, 0x7f, 0xa9, 0x74, 0x4a, 0xc2, 0xf5,
     0x82, 0xa2, 0x08, 0x50, 0xbc, 0x2b, 0x11, 0x41,
     0xed, 0x1b, 0x3e, 0x45, 0x28, 0x59, 0x5a, 0xcc,
     0x90, 0x77, 0x2b, 0xdf, 0x2d, 0x37, 0xdc, 0x8a,
     0x47, 0x13, 0x0b, 0x44, 0xf3, 0x3a, 0x02, 0xe8,
     0x73, 0x0e, 0x5a, 0xd8, 0xe1, 0x66, 0xe8, 0x88}
};
static TestHashVector const testVectorBLAKE2b_4 PROGMEM = {
    "BLAKE2b #4",
    "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
    "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
    {0xce, 0x74, 0x1a, 0xc5, 0x93, 0x0f, 0xe3, 0x46,
     0x81, 0x11, 0x75, 0xc5, 0x22, 0x7b, 0xb7, 0xbf,
     0xcd, 0x47, 0xf4, 0x26, 0x12, 0xfa, 0xe4, 0x6c,
     0x08, 0x09, 0x51, 0x4f, 0x9e, 0x0e, 0x3a, 0x11,
     0xee, 0x17, 0x73, 0x28, 0x71, 0x47, 0xcd, 0xea,
     0xee, 0xdf, 0xf5, 0x07, 0x09, 0xaa, 0x71, 0x63,
     0x41, 0xfe, 0x65, 0x24, 0x0f, 0x4a, 0xd6, 0x77,
     0x7d, 0x6b, 0xfa, 0xf9, 0x72, 0x6e, 0x5e, 0x52}
};
BLAKE2b blake2b;
byte buffer[BLOCK_SIZE + 2];
bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc)
{
    size_t size = strlen(test->data);
    size_t posn, len;
    uint8_t value[HASH_SIZE];
    hash->reset();
    for (posn = 0; posn < size; posn += inc) {
        len = size - posn;
        if (len > inc)
            len = inc;
        hash->update(test->data + posn, len);
    }
    hash->finalize(value, sizeof(value));
    if (memcmp(value, test->hash, sizeof(value)) != 0)
        return false;
    return true;
}
void testHash(Hash *hash, const struct TestHashVector *test)
{
    bool ok;
    TestHashVector vec;
    memcpy_P(&vec, test, sizeof(vec));
    test = &vec;
    Serial.print(test->name);
    Serial.print(" ... ");
    ok  = testHash_N(hash, test, strlen(test->data));
    ok &= testHash_N(hash, test, 1);
    ok &= testHash_N(hash, test, 2);
    ok &= testHash_N(hash, test, 5);
    ok &= testHash_N(hash, test, 8);
    ok &= testHash_N(hash, test, 13);
    ok &= testHash_N(hash, test, 16);
    ok &= testHash_N(hash, test, 24);
    ok &= testHash_N(hash, test, 63);
    ok &= testHash_N(hash, test, 64);
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfHash(Hash *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("Hashing ... ");
    for (size_t posn = 0; posn < sizeof(buffer); ++posn)
        buffer[posn] = (uint8_t)posn;
    hash->reset();
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->update(buffer, sizeof(buffer));
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (sizeof(buffer) * 1000.0));
    Serial.print("us per byte, ");
    Serial.print((sizeof(buffer) * 1000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
// Very simple method for hashing a HMAC inner or outer key.
void hashKey(Hash *hash, const uint8_t *key, size_t keyLen, uint8_t pad)
{
    size_t posn;
    uint8_t buf;
    uint8_t result[HASH_SIZE];
    if (keyLen <= BLOCK_SIZE) {
        hash->reset();
        for (posn = 0; posn < BLOCK_SIZE; ++posn) {
            if (posn < keyLen)
                buf = key[posn] ^ pad;
            else
                buf = pad;
            hash->update(&buf, 1);
        }
    } else {
        hash->reset();
        hash->update(key, keyLen);
        hash->finalize(result, HASH_SIZE);
        hash->reset();
        for (posn = 0; posn < BLOCK_SIZE; ++posn) {
            if (posn < HASH_SIZE)
                buf = result[posn] ^ pad;
            else
                buf = pad;
            hash->update(&buf, 1);
        }
    }
}
void testHMAC(Hash *hash, size_t keyLen)
{
    uint8_t result[HASH_SIZE];
    Serial.print("HMAC-BLAKE2b keysize=");
    Serial.print(keyLen);
    Serial.print(" ... ");
    // 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));
    hash->finalize(result, HASH_SIZE);
    memset(buffer, (uint8_t)keyLen, keyLen);
    hashKey(hash, buffer, keyLen, 0x5C);
    hash->update(result, HASH_SIZE);
    hash->finalize(result, HASH_SIZE);
    // Now use the library to compute the HMAC.
    hash->resetHMAC(buffer, keyLen);
    memset(buffer, 0xBA, sizeof(buffer));
    hash->update(buffer, sizeof(buffer));
    memset(buffer, (uint8_t)keyLen, keyLen);
    hash->finalizeHMAC(buffer, keyLen, buffer, HASH_SIZE);
    // Check the result.
    if (!memcmp(result, buffer, HASH_SIZE))
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
// Deterministic sequences (Fibonacci generator).  From RFC 7693.
static void selftest_seq(uint8_t *out, size_t len, uint32_t seed)
{
    size_t i;
    uint32_t t, a , b;
    a = 0xDEAD4BAD * seed;              // prime
    b = 1;
    for (i = 0; i < len; i++) {         // fill the buf
        t = a + b;
        a = b;
        b = t;
        out[i] = (t >> 24) & 0xFF;
    }
}
// Incremental version of above to save memory.
static void selftest_seq_incremental(BLAKE2b *blake, size_t len, uint32_t seed)
{
    size_t i;
    uint32_t t, a , b;
    a = 0xDEAD4BAD * seed;              // prime
    b = 1;
    for (i = 0; i < len; i++) {         // fill the buf
        t = a + b;
        a = b;
        b = t;
        buffer[i % 128] = (t >> 24) & 0xFF;
        if ((i % 128) == 127)
            blake->update(buffer, 128);
    }
    blake->update(buffer, len % 128);
}
// Run the self-test from Appendix E of RFC 7693.  Most of this code
// is from RFC 7693, with modifications to use the Crypto library.
void testRFC7693()
{
    // Grand hash of hash results.
    static const uint8_t blake2b_res[32] PROGMEM = {
        0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD,
        0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56,
        0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73,
        0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75
    };
    // Parameter sets.
    static const uint8_t b2b_md_len[4] PROGMEM = { 20, 32, 48, 64 };
    static const uint16_t b2b_in_len[6] PROGMEM = { 0, 3, 128, 129, 255, 1024 };
    size_t i, j, outlen, inlen;
    uint8_t md[64], key[64];
    BLAKE2b inner;
    Serial.print("BLAKE2b RFC 7693 ... ");
    // 256-bit hash for testing.
    blake2b.reset(32);
    for (i = 0; i < 4; i++) {
        outlen = pgm_read_byte(&(b2b_md_len[i]));
        for (j = 0; j < 6; j++) {
            inlen = pgm_read_word(&(b2b_in_len[j]));
            inner.reset(outlen);                // unkeyed hash
            selftest_seq_incremental(&inner, inlen, inlen);
            inner.finalize(md, outlen);
            blake2b.update(md, outlen);         // hash the hash
            selftest_seq(key, outlen, outlen);  // keyed hash
            inner.reset(key, outlen, outlen);
            selftest_seq_incremental(&inner, inlen, inlen);
            inner.finalize(md, outlen);
            blake2b.update(md, outlen);         // hash the hash
        }
    }
    // Compute and compare the hash of hashes.
    bool ok = true;
    blake2b.finalize(md, 32);
    for (i = 0; i < 32; i++) {
        if (md[i] != pgm_read_byte(&(blake2b_res[i])))
            ok = false;
    }
    // Report the results.
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfKeyed(BLAKE2b *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("Keyed Reset ... ");
    for (size_t posn = 0; posn < sizeof(buffer); ++posn)
        buffer[posn] = (uint8_t)posn;
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->reset(buffer, hash->hashSize());
        hash->update(buffer, 1);    // To flush the key chunk.
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per op, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" ops per second");
}
void perfFinalize(Hash *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("Finalizing ... ");
    hash->reset();
    hash->update("abc", 3);
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->finalize(buffer, hash->hashSize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per op, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" ops per second");
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.print("State Size ...");
    Serial.println(sizeof(BLAKE2b));
    Serial.println();
    Serial.println("Test Vectors:");
    testHash(&blake2b, &testVectorBLAKE2b_1);
    testHash(&blake2b, &testVectorBLAKE2b_2);
    testHash(&blake2b, &testVectorBLAKE2b_3);
    testHash(&blake2b, &testVectorBLAKE2b_4);
    testHMAC(&blake2b, (size_t)0);
    testHMAC(&blake2b, 1);
    testHMAC(&blake2b, HASH_SIZE);
    testHMAC(&blake2b, BLOCK_SIZE);
    testHMAC(&blake2b, BLOCK_SIZE + 1);
    testHMAC(&blake2b, BLOCK_SIZE + 2);
    testRFC7693();
    Serial.println();
    Serial.println("Performance Tests:");
    perfHash(&blake2b);
    perfKeyed(&blake2b);
    perfFinalize(&blake2b);
}
void loop()
{
}
src/modules/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino
New file
@@ -0,0 +1,429 @@
/*
 * 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.
 */
/*
This example runs tests on the BLAKE2s implementation to verify correct behaviour.
*/
#include <Crypto.h>
#include <BLAKE2s.h>
#include <string.h>
#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#define HASH_SIZE 32
#define BLOCK_SIZE 64
struct TestHashVector
{
    const char *name;
    const char *data;
    uint8_t hash[HASH_SIZE];
};
// Test vectors generated with the reference implementation of BLAKE2s.
static TestHashVector const testVectorBLAKE2s_1 = {
    "BLAKE2s #1",
    "",
    {0x69, 0x21, 0x7a, 0x30, 0x79, 0x90, 0x80, 0x94,
     0xe1, 0x11, 0x21, 0xd0, 0x42, 0x35, 0x4a, 0x7c,
     0x1f, 0x55, 0xb6, 0x48, 0x2c, 0xa1, 0xa5, 0x1e,
     0x1b, 0x25, 0x0d, 0xfd, 0x1e, 0xd0, 0xee, 0xf9}
};
static TestHashVector const testVectorBLAKE2s_2 = {
    "BLAKE2s #2",
    "abc",
    {0x50, 0x8c, 0x5e, 0x8c, 0x32, 0x7c, 0x14, 0xe2,
     0xe1, 0xa7, 0x2b, 0xa3, 0x4e, 0xeb, 0x45, 0x2f,
     0x37, 0x45, 0x8b, 0x20, 0x9e, 0xd6, 0x3a, 0x29,
     0x4d, 0x99, 0x9b, 0x4c, 0x86, 0x67, 0x59, 0x82}
};
static TestHashVector const testVectorBLAKE2s_3 = {
    "BLAKE2s #3",
    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
    {0x6f, 0x4d, 0xf5, 0x11, 0x6a, 0x6f, 0x33, 0x2e,
     0xda, 0xb1, 0xd9, 0xe1, 0x0e, 0xe8, 0x7d, 0xf6,
     0x55, 0x7b, 0xea, 0xb6, 0x25, 0x9d, 0x76, 0x63,
     0xf3, 0xbc, 0xd5, 0x72, 0x2c, 0x13, 0xf1, 0x89}
};
static TestHashVector const testVectorBLAKE2s_4 = {
    "BLAKE2s #4",
    "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
    "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
    {0x35, 0x8d, 0xd2, 0xed, 0x07, 0x80, 0xd4, 0x05,
     0x4e, 0x76, 0xcb, 0x6f, 0x3a, 0x5b, 0xce, 0x28,
     0x41, 0xe8, 0xe2, 0xf5, 0x47, 0x43, 0x1d, 0x4d,
     0x09, 0xdb, 0x21, 0xb6, 0x6d, 0x94, 0x1f, 0xc7}
};
BLAKE2s blake2s;
byte buffer[128];
bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc)
{
    size_t size = strlen(test->data);
    size_t posn, len;
    uint8_t value[HASH_SIZE];
    hash->reset();
    for (posn = 0; posn < size; posn += inc) {
        len = size - posn;
        if (len > inc)
            len = inc;
        hash->update(test->data + posn, len);
    }
    hash->finalize(value, sizeof(value));
    if (memcmp(value, test->hash, sizeof(value)) != 0)
        return false;
    return true;
}
void testHash(Hash *hash, const struct TestHashVector *test)
{
    bool ok;
    Serial.print(test->name);
    Serial.print(" ... ");
    ok  = testHash_N(hash, test, strlen(test->data));
    ok &= testHash_N(hash, test, 1);
    ok &= testHash_N(hash, test, 2);
    ok &= testHash_N(hash, test, 5);
    ok &= testHash_N(hash, test, 8);
    ok &= testHash_N(hash, test, 13);
    ok &= testHash_N(hash, test, 16);
    ok &= testHash_N(hash, test, 24);
    ok &= testHash_N(hash, test, 63);
    ok &= testHash_N(hash, test, 64);
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfHash(Hash *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("Hashing ... ");
    for (size_t posn = 0; posn < sizeof(buffer); ++posn)
        buffer[posn] = (uint8_t)posn;
    hash->reset();
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->update(buffer, sizeof(buffer));
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (sizeof(buffer) * 1000.0));
    Serial.print("us per byte, ");
    Serial.print((sizeof(buffer) * 1000.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
// Very simple method for hashing a HMAC inner or outer key.
void hashKey(Hash *hash, const uint8_t *key, size_t keyLen, uint8_t pad)
{
    size_t posn;
    uint8_t buf;
    uint8_t result[HASH_SIZE];
    if (keyLen <= BLOCK_SIZE) {
        hash->reset();
        for (posn = 0; posn < BLOCK_SIZE; ++posn) {
            if (posn < keyLen)
                buf = key[posn] ^ pad;
            else
                buf = pad;
            hash->update(&buf, 1);
        }
    } else {
        hash->reset();
        hash->update(key, keyLen);
        hash->finalize(result, HASH_SIZE);
        hash->reset();
        for (posn = 0; posn < BLOCK_SIZE; ++posn) {
            if (posn < HASH_SIZE)
                buf = result[posn] ^ pad;
            else
                buf = pad;
            hash->update(&buf, 1);
        }
    }
}
void testHMAC(Hash *hash, size_t keyLen)
{
    uint8_t result[HASH_SIZE];
    Serial.print("HMAC-BLAKE2s keysize=");
    Serial.print(keyLen);
    Serial.print(" ... ");
    // 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));
    hash->finalize(result, HASH_SIZE);
    memset(buffer, (uint8_t)keyLen, keyLen);
    hashKey(hash, buffer, keyLen, 0x5C);
    hash->update(result, HASH_SIZE);
    hash->finalize(result, HASH_SIZE);
    // Now use the library to compute the HMAC.
    hash->resetHMAC(buffer, keyLen);
    memset(buffer, 0xBA, sizeof(buffer));
    hash->update(buffer, sizeof(buffer));
    memset(buffer, (uint8_t)keyLen, keyLen);
    hash->finalizeHMAC(buffer, keyLen, buffer, HASH_SIZE);
    // Check the result.
    if (!memcmp(result, buffer, HASH_SIZE))
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
// Deterministic sequences (Fibonacci generator).  From RFC 7693.
static void selftest_seq(uint8_t *out, size_t len, uint32_t seed)
{
    size_t i;
    uint32_t t, a , b;
    a = 0xDEAD4BAD * seed;              // prime
    b = 1;
    for (i = 0; i < len; i++) {         // fill the buf
        t = a + b;
        a = b;
        b = t;
        out[i] = (t >> 24) & 0xFF;
    }
}
// Incremental version of above to save memory.
static void selftest_seq_incremental(BLAKE2s *blake, size_t len, uint32_t seed)
{
    size_t i;
    uint32_t t, a , b;
    a = 0xDEAD4BAD * seed;              // prime
    b = 1;
    for (i = 0; i < len; i++) {         // fill the buf
        t = a + b;
        a = b;
        b = t;
        buffer[i % 128] = (t >> 24) & 0xFF;
        if ((i % 128) == 127)
            blake->update(buffer, sizeof(buffer));
    }
    blake->update(buffer, len % 128);
}
// Run the self-test from Appendix E of RFC 7693.  Most of this code
// is from RFC 7693, with modifications to use the Crypto library.
void testRFC7693()
{
    // Grand hash of hash results.
    static const uint8_t blake2s_res[32] PROGMEM = {
        0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD,
        0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC,
        0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87,
        0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE
    };
    // Parameter sets.
    static const uint8_t b2s_md_len[4] PROGMEM = { 16, 20, 28, 32 };
    static const uint16_t b2s_in_len[6] PROGMEM = { 0,  3,  64, 65, 255, 1024 };
    size_t i, j, outlen, inlen;
    uint8_t md[32], key[32];
    BLAKE2s inner;
    Serial.print("BLAKE2s RFC 7693 ... ");
    // 256-bit hash for testing.
    blake2s.reset(32);
    for (i = 0; i < 4; i++) {
        outlen = pgm_read_byte(&(b2s_md_len[i]));
        for (j = 0; j < 6; j++) {
            inlen = pgm_read_word(&(b2s_in_len[j]));
            inner.reset(outlen);                // unkeyed hash
            selftest_seq_incremental(&inner, inlen, inlen);
            inner.finalize(md, outlen);
            blake2s.update(md, outlen);         // hash the hash
            selftest_seq(key, outlen, outlen);  // keyed hash
            inner.reset(key, outlen, outlen);
            selftest_seq_incremental(&inner, inlen, inlen);
            inner.finalize(md, outlen);
            blake2s.update(md, outlen);         // hash the hash
        }
    }
    // Compute and compare the hash of hashes.
    bool ok = true;
    blake2s.finalize(md, 32);
    for (i = 0; i < 32; i++) {
        if (md[i] != pgm_read_byte(&(blake2s_res[i])))
            ok = false;
    }
    // Report the results.
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfFinalize(Hash *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("Finalizing ... ");
    hash->reset();
    hash->update("abc", 3);
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->finalize(buffer, hash->hashSize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per op, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" ops per second");
}
void perfKeyed(BLAKE2s *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("Keyed Reset ... ");
    for (size_t posn = 0; posn < sizeof(buffer); ++posn)
        buffer[posn] = (uint8_t)posn;
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->reset(buffer, hash->hashSize());
        hash->update(buffer, 1);    // To flush the key chunk.
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per op, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" ops per second");
}
void perfHMAC(Hash *hash)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print("HMAC Reset ... ");
    for (size_t posn = 0; posn < sizeof(buffer); ++posn)
        buffer[posn] = (uint8_t)posn;
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->resetHMAC(buffer, hash->hashSize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per op, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" ops per second");
    Serial.print("HMAC Finalize ... ");
    hash->resetHMAC(buffer, hash->hashSize());
    hash->update("abc", 3);
    start = micros();
    for (count = 0; count < 1000; ++count) {
        hash->finalizeHMAC(buffer, hash->hashSize(), buffer, hash->hashSize());
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per op, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" ops per second");
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.print("State Size ... ");
    Serial.println(sizeof(BLAKE2s));
    Serial.println();
    Serial.println("Test Vectors:");
    testHash(&blake2s, &testVectorBLAKE2s_1);
    testHash(&blake2s, &testVectorBLAKE2s_2);
    testHash(&blake2s, &testVectorBLAKE2s_3);
    testHash(&blake2s, &testVectorBLAKE2s_4);
    testHMAC(&blake2s, (size_t)0);
    testHMAC(&blake2s, 1);
    testHMAC(&blake2s, HASH_SIZE);
    testHMAC(&blake2s, BLOCK_SIZE);
    testHMAC(&blake2s, BLOCK_SIZE + 1);
    testHMAC(&blake2s, sizeof(buffer));
    testRFC7693();
    Serial.println();
    Serial.println("Performance Tests:");
    perfHash(&blake2s);
    perfFinalize(&blake2s);
    perfKeyed(&blake2s);
    perfHMAC(&blake2s);
}
void loop()
{
}
src/modules/Crypto/examples/TestBigNumberUtil/TestBigNumberUtil.ino
New file
@@ -0,0 +1,378 @@
/*
 * 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.
 */
/*
This example runs tests on the utility functions in BigNumberUtil.
*/
#include <Crypto.h>
#include <BigNumberUtil.h>
#include <utility/ProgMemUtil.h>
#include <string.h>
#define NUM_SIZE_512BIT (64 / sizeof(limb_t))
#define LIMB_BITS       (sizeof(limb_t) * 8)
// Convert a decimal string in program memory into a big number.
void fromString(limb_t *x, size_t xsize, const char *str)
{
    uint8_t ch;
    size_t posn;
    memset(x, 0, sizeof(limb_t) * 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.
            dlimb_t carry = ch - '0';
            for (posn = 0; posn < xsize; ++posn) {
                carry += ((dlimb_t)x[posn]) * 10U;
                x[posn] = (limb_t)carry;
                carry >>= LIMB_BITS;
            }
        }
        ++str;
    }
}
// Convert a decimal string in program memory into a byte array.
void bytesFromString(uint8_t *x, size_t xsize, const char *str)
{
    uint8_t ch;
    size_t posn;
    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.
            uint16_t carry = ch - '0';
            for (posn = 0; posn < xsize; ++posn) {
                carry += ((uint16_t)x[posn]) * 10U;
                x[posn] = (uint8_t)carry;
                carry >>= 8;
            }
        }
        ++str;
    }
}
// Compare two big numbers.  Returns -1, 0, or 1.
int compare(const limb_t *x, size_t xsize, const limb_t *y, size_t ysize)
{
    limb_t a, b;
    while (xsize > 0 || ysize > 0) {
        if (xsize > ysize) {
            --xsize;
            a = x[xsize];
            b = 0;
        } else if (ysize > xsize) {
            --ysize;
            a = 0;
            b = y[ysize];
        } else {
            --xsize;
            --ysize;
            a = x[xsize];
            b = y[ysize];
        }
        if (a < b)
            return -1;
        else if (a > b)
            return 1;
    }
    return 0;
}
// Compare two numbers where one is a decimal string.  Returns -1, 0, or 1.
int compare(const limb_t *x, size_t xsize, const char *y)
{
    limb_t val[NUM_SIZE_512BIT];
    fromString(val, NUM_SIZE_512BIT, y);
    return compare(x, xsize, val, NUM_SIZE_512BIT);
}
// Prints a number in hexadecimal.
void printNumber(const char *name, const limb_t *x, size_t xsize)
{
    static const char hexchars[] = "0123456789ABCDEF";
    Serial.print(name);
    Serial.print(" = ");
    for (size_t posn = 0; posn < xsize; ++posn) {
        for (uint8_t bit = LIMB_BITS; bit > 0; ) {
            bit -= 4;
            Serial.print(hexchars[(x[xsize - 1 - posn] >> bit) & 0x0F]);
        }
        Serial.print(' ');
    }
    Serial.println();
}
// Standard numbers that are useful in big number tests.
char const num_0[] PROGMEM = "0";
char const num_1[] PROGMEM = "1";
char const num_2[] PROGMEM = "2";
char const num_4[] PROGMEM = "4";
char const num_5[] PROGMEM = "5";
char const num_128[] PROGMEM = "128";
char const num_256[] PROGMEM = "256";
char const num_2_64_m7[] PROGMEM = "18446744073709551609"; // 2^64 - 7
char const num_2_129_m5[] PROGMEM = "680564733841876926926749214863536422907"; // 2^129 - 5
char const num_pi_77[] PROGMEM = "31415926535897932384626433832795028841971693993751058209749445923078164062862"; // 77 digits of pi
char const num_pi_154[] PROGMEM = "3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481"; // 154 digits of pi
char const num_2_255_m253[] PROGMEM = "57896044618658097711785492504343953926634992332820282019728792003956564819715"; // 2^255 - 253
char const num_2_255_m20[] PROGMEM = "57896044618658097711785492504343953926634992332820282019728792003956564819948"; // 2^255 - 20
char const num_2_255_m19[] PROGMEM = "57896044618658097711785492504343953926634992332820282019728792003956564819949"; // 2^255 - 19
char const num_2_255_m19_x2[] PROGMEM = "115792089237316195423570985008687907853269984665640564039457584007913129639898"; // (2^255 - 19) * 2
char const num_a24[] PROGMEM = "121665";
char const num_2_512_m19[] PROGMEM = "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084077"; // (2^512 - 19)
// Table of useful numbers.
const char * const numbers[] = {
    num_0,
    num_1,
    num_2,
    num_4,
    num_5,
    num_128,
    num_256,
    num_2_64_m7,
    num_2_129_m5,
    num_pi_77,
    num_2_255_m253,
    num_2_255_m20,
    num_pi_154,
    num_2_512_m19,
    0
};
#define numbers_count   ((sizeof(numbers) / sizeof(numbers[0])) - 1)
#define foreach_number(var) \
    const char *var = numbers[0]; \
    for (unsigned index##var = 0; index##var < numbers_count; \
         ++index##var, var = numbers[index##var])
// Print a decimal string from program memory.
void printProgMem(const char *str)
{
    uint8_t ch;
    while ((ch = pgm_read_byte((uint8_t *)str)) != '\0') {
        Serial.print((char)ch);
        ++str;
    }
}
// Determine if an array consists of all zero bytes.
static bool isAllZero(const uint8_t *bytes, size_t size)
{
    while (size > 0) {
        if (*bytes++ != 0)
            return false;
        --size;
    }
    return true;
}
// Determine if an array consists of all 0xBA bytes.
static bool isAllBad(const uint8_t *bytes, size_t size)
{
    while (size > 0) {
        if (*bytes++ != 0xBA)
            return false;
        --size;
    }
    return true;
}
#if !BIGNUMBER_LIMB_8BIT
static bool isAllBad(const limb_t *limbs, size_t size)
{
    return isAllBad((uint8_t *)limbs, size * sizeof(limb_t));
}
#endif
// Truncate the limb representation of a number to a specific byte length.
static void truncateNumber(limb_t *limbs, size_t bytes)
{
    size_t posn = NUM_SIZE_512BIT * sizeof(limb_t);
    size_t posn2;
    limb_t mask;
    while (posn > bytes) {
        --posn;
        posn2 = posn % sizeof(limb_t);
        if (posn2 == 0)
            mask = 0;
        else if (posn2 == 1)
            mask = 0x000000FF;
        else if (posn2 == 2)
            mask = 0x0000FFFF;
#if BIGNUMBER_LIMB_64BIT
        else if (posn2 == 3)
            mask = 0x00FFFFFF;
        else if (posn2 == 4)
            mask = 0xFFFFFFFF;
        else if (posn2 == 5)
            mask = 0xFFFFFFFFFF;
        else if (posn2 == 6)
            mask = 0xFFFFFFFFFFFF;
        else
            mask = 0xFFFFFFFFFFFFFF;
#else
        else
            mask = 0x00FFFFFF;
#endif
        limbs[posn / sizeof(limb_t)] &= mask;
    }
}
// Test byte array pack and unpack operations.
void testPackUnpack(void)
{
    limb_t num[NUM_SIZE_512BIT];
    limb_t tnum[NUM_SIZE_512BIT];
    limb_t limbs[NUM_SIZE_512BIT];
    uint8_t bytes[64];
    uint8_t expected[64];
    size_t posn;
    uint8_t temp;
    foreach_number(x) {
        // What number are we on?
        Serial.print("pack ");
        printProgMem(x);
        Serial.print(": ");
        Serial.flush();
        bool ok = true;
        // Convert the number into limbs and bytes in a simple way.
        fromString(num, NUM_SIZE_512BIT, x);
        bytesFromString(expected, sizeof(expected), x);
        // Check packLE() and unpackLE() against the expected values.
        for (posn = 0; posn < 64; ++posn) {
            memset(bytes, 0xBA, sizeof(bytes));
            BigNumberUtil::packLE(bytes, posn, num, NUM_SIZE_512BIT);
            if (memcmp(bytes, expected, posn) != 0)
                ok = false;
            if (!isAllBad(bytes + posn, sizeof(bytes) - posn))
                ok = false;
        }
        for (posn = 0; posn < NUM_SIZE_512BIT; ++posn) {
            BigNumberUtil::packLE(bytes, sizeof(bytes), num, posn);
            if (memcmp(bytes, expected, posn * sizeof(limb_t)) != 0)
                ok = false;
            if (!isAllZero(bytes + posn * sizeof(limb_t), sizeof(bytes) - posn * sizeof(limb_t)))
                ok = false;
        }
        for (posn = 0; posn < NUM_SIZE_512BIT; ++posn) {
            memset(limbs, 0xBA, sizeof(limbs));
            BigNumberUtil::unpackLE(limbs, posn, expected, sizeof(expected));
            if (memcmp(limbs, num, posn) != 0)
                ok = false;
            if (!isAllBad(limbs + posn, NUM_SIZE_512BIT - posn))
                ok = false;
        }
        for (posn = 0; posn < 64; ++posn) {
            memset(limbs, 0xBA, sizeof(limbs));
            BigNumberUtil::unpackLE(limbs, NUM_SIZE_512BIT,
                                    expected, sizeof(expected) - posn);
            memcpy(tnum, num, sizeof(num));
            truncateNumber(tnum, sizeof(expected) - posn);
            if (memcmp(limbs, tnum, NUM_SIZE_512BIT) != 0)
                ok = false;
        }
        for (posn = 0; posn < NUM_SIZE_512BIT; ++posn) {
            memset(limbs, 0xBA, sizeof(limbs));
            BigNumberUtil::unpackLE(limbs, posn, expected, sizeof(expected));
            if (memcmp(limbs, num, posn * sizeof(limb_t)) != 0)
                ok = false;
            if (!isAllBad(limbs + posn, NUM_SIZE_512BIT - posn))
                ok = false;
        }
        // Swap the expected byte array into big-endian order.
        for (posn = 0; posn < 32; ++posn) {
            temp = expected[posn];
            expected[posn] = expected[63 - posn];
            expected[63 - posn] = temp;
        }
        // Check packBE() and unpackBE() against the expected values.
        for (posn = 0; posn < 64; ++posn) {
            memset(bytes, 0xBA, sizeof(bytes));
            BigNumberUtil::packBE(bytes, posn, num, NUM_SIZE_512BIT);
            if (memcmp(bytes, expected + 64 - posn, posn) != 0)
                ok = false;
            if (!isAllBad(bytes + posn, sizeof(bytes) - posn))
                ok = false;
        }
        for (posn = 0; posn < NUM_SIZE_512BIT; ++posn) {
            BigNumberUtil::packBE(bytes, sizeof(bytes), num, posn);
            if (memcmp(bytes + 64 - posn * sizeof(limb_t),
                       expected + 64 - posn * sizeof(limb_t),
                       posn * sizeof(limb_t)) != 0)
                ok = false;
            if (!isAllZero(bytes, sizeof(bytes) - posn * sizeof(limb_t)))
                ok = false;
        }
        for (posn = 0; posn < NUM_SIZE_512BIT; ++posn) {
            memset(limbs, 0xBA, sizeof(limbs));
            BigNumberUtil::unpackBE(limbs, posn, expected, sizeof(expected));
            if (memcmp(limbs, num, posn) != 0)
                ok = false;
            if (!isAllBad(limbs + posn, NUM_SIZE_512BIT - posn))
                ok = false;
        }
        for (posn = 0; posn < 64; ++posn) {
            memset(limbs, 0xBA, sizeof(limbs));
            BigNumberUtil::unpackBE(limbs, NUM_SIZE_512BIT,
                                    expected + posn, sizeof(expected) - posn);
            memcpy(tnum, num, sizeof(num));
            truncateNumber(tnum, sizeof(expected) - posn);
            if (memcmp(limbs, tnum, NUM_SIZE_512BIT) != 0)
                ok = false;
        }
        for (posn = 0; posn < NUM_SIZE_512BIT; ++posn) {
            memset(limbs, 0xBA, sizeof(limbs));
            BigNumberUtil::unpackBE(limbs, posn, expected, sizeof(expected));
            if (memcmp(limbs, num, posn * sizeof(limb_t)) != 0)
                ok = false;
            if (!isAllBad(limbs + posn, NUM_SIZE_512BIT - posn))
                ok = false;
        }
        // Report the results.
        if (ok)
            Serial.println("ok");
        else
            Serial.println("failed");
    }
}
void setup()
{
    Serial.begin(9600);
    testPackUnpack();
}
void loop()
{
}
src/modules/Crypto/examples/TestCTR/TestCTR.ino
New file
@@ -0,0 +1,231 @@
/*
 * 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.
 */
/*
This example runs tests on the CTR implementation to verify correct behaviour.
*/
#include <Crypto.h>
#include <AES.h>
#include <CTR.h>
#include <string.h>
#define MAX_PLAINTEXT_SIZE  36
#define MAX_CIPHERTEXT_SIZE 36
struct TestVector
{
    const char *name;
    byte key[16];
    byte plaintext[MAX_PLAINTEXT_SIZE];
    byte ciphertext[MAX_CIPHERTEXT_SIZE];
    byte iv[16];
    size_t size;
};
// Test vectors for AES-128 in CTR mode from RFC 3686.
static TestVector const testVectorAES128CTR1 = {
    .name        = "AES-128-CTR #1",
    .key         = {0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC,
                    0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E},
    .plaintext   = {0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62,
                    0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67},
    .ciphertext  = {0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79,
                    0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8},
    .iv          = {0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
    .size        = 16
};
static TestVector const testVectorAES128CTR2 = {
    .name        = "AES-128-CTR #2",
    .key         = {0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7,
                    0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63},
    .plaintext   = {0x00, 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
    .ciphertext  = {0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9,
                    0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88,
                    0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8,
                    0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28},
    .iv          = {0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59,
                    0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01},
    .size        = 32
};
static TestVector const testVectorAES128CTR3 = {
    .name        = "AES-128-CTR #3",
    .key         = {0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8,
                    0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC},
    .plaintext   = {0x00, 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
                    0x20, 0x21, 0x22, 0x23},
    .ciphertext  = {0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9,
                    0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7,
                    0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36,
                    0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53,
                    0x25, 0xB2, 0x07, 0x2F},
    .iv          = {0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F,
                    0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01},
    .size        = 36
};
CTR<AES128> ctraes128;
byte buffer[128];
bool testCipher_N(Cipher *cipher, const struct TestVector *test, size_t inc)
{
    byte output[MAX_CIPHERTEXT_SIZE];
    size_t posn, len;
    cipher->clear();
    if (!cipher->setKey(test->key, cipher->keySize())) {
        Serial.print("setKey ");
        return false;
    }
    if (!cipher->setIV(test->iv, cipher->ivSize())) {
        Serial.print("setIV ");
        return false;
    }
    memset(output, 0xBA, sizeof(output));
    for (posn = 0; posn < test->size; posn += inc) {
        len = test->size - posn;
        if (len > inc)
            len = inc;
        cipher->encrypt(output + posn, test->plaintext + posn, len);
    }
    if (memcmp(output, test->ciphertext, test->size) != 0) {
        Serial.print(output[0], HEX);
        Serial.print("->");
        Serial.print(test->ciphertext[0], HEX);
        return false;
    }
    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, cipher->ivSize());
    for (posn = 0; posn < test->size; posn += inc) {
        len = test->size - posn;
        if (len > inc)
            len = inc;
        cipher->decrypt(output + posn, test->ciphertext + posn, len);
    }
    if (memcmp(output, test->plaintext, test->size) != 0)
        return false;
    return true;
}
void testCipher(Cipher *cipher, const struct TestVector *test)
{
    bool ok;
    Serial.print(test->name);
    Serial.print(" ... ");
    ok  = testCipher_N(cipher, test, test->size);
    ok &= testCipher_N(cipher, test, 1);
    ok &= testCipher_N(cipher, test, 2);
    ok &= testCipher_N(cipher, test, 5);
    ok &= testCipher_N(cipher, test, 8);
    ok &= testCipher_N(cipher, test, 13);
    ok &= testCipher_N(cipher, test, 16);
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfCipherEncrypt(const char *name, Cipher *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print(name);
    Serial.print(" ... ");
    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, cipher->ivSize());
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->encrypt(buffer, buffer, sizeof(buffer));
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (sizeof(buffer) * 500.0));
    Serial.print("us per byte, ");
    Serial.print((sizeof(buffer) * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
void perfCipherDecrypt(const char *name, Cipher *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    Serial.print(name);
    Serial.print(" ... ");
    cipher->setKey(test->key, cipher->keySize());
    cipher->setIV(test->iv, cipher->ivSize());
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->decrypt(buffer, buffer, sizeof(buffer));
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (sizeof(buffer) * 500.0));
    Serial.print("us per byte, ");
    Serial.print((sizeof(buffer) * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.println("Test Vectors:");
    testCipher(&ctraes128, &testVectorAES128CTR1);
    testCipher(&ctraes128, &testVectorAES128CTR2);
    testCipher(&ctraes128, &testVectorAES128CTR3);
    Serial.println();
    Serial.println("Performance Tests:");
    perfCipherEncrypt("AES-128-CTR Encrypt", &ctraes128, &testVectorAES128CTR1);
    perfCipherDecrypt("AES-128-CTR Decrypt", &ctraes128, &testVectorAES128CTR1);
}
void loop()
{
}
src/modules/Crypto/examples/TestChaCha/TestChaCha.ino
New file
@@ -0,0 +1,422 @@
/*
 * 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.
 */
/*
This example runs tests on the ChaCha implementation to verify correct behaviour.
*/
#include <Crypto.h>
#include <ChaCha.h>
#include <string.h>
#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#define MAX_PLAINTEXT_SIZE  64
#define MAX_CIPHERTEXT_SIZE 64
struct TestVector
{
    const char *name;
    byte key[32];
    size_t keySize;
    uint8_t rounds;
    byte plaintext[MAX_PLAINTEXT_SIZE];
    byte ciphertext[MAX_CIPHERTEXT_SIZE];
    byte iv[8];
    byte counter[8];
    size_t size;
};
// Use the test vectors from section 9 of the Salsa20 specification,
// http://cr.yp.to/snuffle/spec.pdf, but modify the ciphertext to
// the expected output from ChaCha20/12/8.  Unfortunately the ChaCha
// specification doesn't contain test vectors - these were generated
// using the reference implementation from http://cr.yp.to/chacha.html.
static TestVector const testVectorChaCha20_128 PROGMEM = {
    .name        = "ChaCha20 128-bit",
    .key         = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
    .keySize     = 16,
    .rounds      = 20,
    .plaintext   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    .ciphertext  = {0x1C, 0x91, 0xE7, 0x99, 0x71, 0xC0, 0x1C, 0x2A,
                    0xEC, 0xE9, 0x24, 0x35, 0xB1, 0x6E, 0xBF, 0xFD,
                    0x33, 0x05, 0xCC, 0x17, 0x24, 0x9D, 0x66, 0xA7,
                    0xA0, 0xCA, 0xB8, 0x36, 0x03, 0xA6, 0x9D, 0x93,
                    0x9A, 0x4C, 0x10, 0x40, 0xD9, 0x2A, 0x86, 0x78,
                    0x3A, 0xAD, 0x71, 0x87, 0x55, 0x9F, 0x5B, 0x9A,
                    0x68, 0x52, 0xA0, 0xAD, 0x59, 0xAE, 0x04, 0x10,
                    0x25, 0x74, 0x5C, 0x05, 0x62, 0x78, 0xF4, 0x8A},
    .iv          = {101,102,103,104,105,106,107,108},
    .counter     = {109, 110, 111, 112, 113, 114, 115, 116},
    .size        = 64
};
static TestVector const testVectorChaCha20_256 PROGMEM = {
    .name        = "ChaCha20 256-bit",
    .key         = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
                    201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
                    211, 212, 213, 214, 215, 216},
    .keySize     = 32,
    .rounds      = 20,
    .plaintext   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    .ciphertext  = {0x2A, 0x7E, 0x73, 0xC2, 0x2A, 0xE5, 0xCF, 0x4E,
                    0x21, 0x75, 0xB1, 0x26, 0x38, 0x3F, 0x60, 0x84,
                    0x11, 0x25, 0xFC, 0xAD, 0xFD, 0x16, 0x54, 0xF2,
                    0xD7, 0x8C, 0x5D, 0x49, 0x8D, 0x96, 0xBE, 0x15,
                    0xC9, 0x00, 0x12, 0x09, 0x14, 0x43, 0x2D, 0x6D,
                    0x64, 0x33, 0x88, 0xA6, 0x16, 0x39, 0x86, 0xFD,
                    0xD8, 0x85, 0x4D, 0x76, 0x42, 0xEC, 0x0A, 0x0C,
                    0x8A, 0xF2, 0x99, 0x2E, 0x54, 0xAE, 0xB4, 0xD9},
    .iv          = {101,102,103,104,105,106,107,108},
    .counter     = {109, 110, 111, 112, 113, 114, 115, 116},
    .size        = 64
};
static TestVector const testVectorChaCha12_128 PROGMEM = {
    .name        = "ChaCha12 128-bit",
    .key         = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
    .keySize     = 16,
    .rounds      = 12,
    .plaintext   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    .ciphertext  = {0xCB, 0xC1, 0xCF, 0x63, 0xE8, 0xD0, 0x62, 0x83,
                    0xFC, 0x12, 0x87, 0x8C, 0x62, 0x09, 0x5B, 0xF8,
                    0x84, 0x93, 0x30, 0xC6, 0xE6, 0x26, 0x87, 0x99,
                    0xB0, 0xD9, 0xC1, 0xE1, 0xD7, 0x58, 0xCA, 0x05,
                    0xFE, 0x46, 0x40, 0xD1, 0xDC, 0x14, 0x68, 0x3C,
                    0xFF, 0x25, 0xF7, 0x70, 0x5F, 0xBF, 0x37, 0xC5,
                    0x29, 0x8F, 0x3C, 0x55, 0x74, 0xDF, 0xF7, 0x49,
                    0x8D, 0xD8, 0xE9, 0xBA, 0x5D, 0xF1, 0x9F, 0xA5},
    .iv          = {101,102,103,104,105,106,107,108},
    .counter     = {109, 110, 111, 112, 113, 114, 115, 116},
    .size        = 64
};
static TestVector const testVectorChaCha12_256 PROGMEM = {
    .name        = "ChaCha12 256-bit",
    .key         = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
                    201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
                    211, 212, 213, 214, 215, 216},
    .keySize     = 32,
    .rounds      = 12,
    .plaintext   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    .ciphertext  = {0xB8, 0x49, 0xD4, 0x70, 0xE0, 0xFF, 0x57, 0x12,
                    0x95, 0xBF, 0xD9, 0xCD, 0x26, 0xFD, 0x4D, 0x6E,
                    0x70, 0xA2, 0xBC, 0x58, 0x63, 0xF6, 0x2C, 0xC3,
                    0xC7, 0x1C, 0x9B, 0x1A, 0x54, 0xDC, 0xF9, 0xF8,
                    0xFD, 0x59, 0xEA, 0xC9, 0xC3, 0x10, 0xA1, 0xDE,
                    0xD1, 0x53, 0x84, 0xD6, 0x8D, 0xC6, 0x61, 0x09,
                    0x2E, 0x62, 0x14, 0xC5, 0x77, 0x4B, 0x6B, 0x5B,
                    0x0D, 0x35, 0xE6, 0x17, 0x41, 0x51, 0xA6, 0xA4},
    .iv          = {101,102,103,104,105,106,107,108},
    .counter     = {109, 110, 111, 112, 113, 114, 115, 116},
    .size        = 64
};
static TestVector const testVectorChaCha8_128 PROGMEM = {
    .name        = "ChaCha8 128-bit",
    .key         = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
    .keySize     = 16,
    .rounds      = 8,
    .plaintext   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    .ciphertext  = {0x76, 0x42, 0x84, 0xB4, 0x87, 0x1F, 0x54, 0xAE,
                    0x33, 0xBF, 0x79, 0x3C, 0xE2, 0x78, 0x5B, 0x4D,
                    0xE7, 0x90, 0xF3, 0x8C, 0xB8, 0xF4, 0xA1, 0x56,
                    0x87, 0x8B, 0x54, 0x06, 0xBE, 0x5A, 0x1B, 0x1C,
                    0x30, 0x31, 0xD3, 0xCD, 0x90, 0x34, 0xC8, 0x93,
                    0x2C, 0x0A, 0x5E, 0xC9, 0x4A, 0x1A, 0x66, 0x4C,
                    0x28, 0x94, 0xA9, 0x61, 0xBB, 0xB4, 0xF0, 0x2D,
                    0x59, 0x73, 0x9F, 0xC9, 0xF1, 0xF0, 0x66, 0x05},
    .iv          = {101,102,103,104,105,106,107,108},
    .counter     = {109, 110, 111, 112, 113, 114, 115, 116},
    .size        = 64
};
static TestVector const testVectorChaCha8_256 PROGMEM = {
    .name        = "ChaCha8 256-bit",
    .key         = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
                    201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
                    211, 212, 213, 214, 215, 216},
    .keySize     = 32,
    .rounds      = 8,
    .plaintext   = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    .ciphertext  = {0x38, 0x0F, 0x75, 0xD6, 0x32, 0xF8, 0xBB, 0x2C,
                    0x44, 0x81, 0xF4, 0x27, 0x90, 0xB8, 0xAA, 0xE3,
                    0x09, 0xD1, 0xB9, 0x55, 0xC2, 0xF5, 0x85, 0x27,
                    0xBB, 0x8F, 0x43, 0x00, 0x68, 0x2B, 0x2A, 0x1B,
                    0x7A, 0xC1, 0x5B, 0xC3, 0xA3, 0xFF, 0x29, 0xC9,
                    0xD2, 0x95, 0x98, 0xF6, 0x3C, 0xAC, 0x9B, 0x2C,
                    0xA3, 0xF1, 0x40, 0x1E, 0xFA, 0x7C, 0xAC, 0xA3,
                    0xB1, 0x61, 0x27, 0x50, 0xBB, 0x03, 0x24, 0x36},
    .iv          = {101,102,103,104,105,106,107,108},
    .counter     = {109, 110, 111, 112, 113, 114, 115, 116},
    .size        = 64
};
TestVector testVector;
ChaCha chacha;
byte buffer[128];
bool testCipher_N(ChaCha *cipher, const struct TestVector *test, size_t inc)
{
    byte output[MAX_CIPHERTEXT_SIZE];
    size_t posn, len;
    cipher->clear();
    if (!cipher->setKey(test->key, test->keySize)) {
        Serial.print("setKey ");
        return false;
    }
    if (!cipher->setIV(test->iv, cipher->ivSize())) {
        Serial.print("setIV ");
        return false;
    }
    if (!cipher->setCounter(test->counter, 8)) {
        Serial.print("setCounter ");
        return false;
    }
    memset(output, 0xBA, sizeof(output));
    for (posn = 0; posn < test->size; posn += inc) {
        len = test->size - posn;
        if (len > inc)
            len = inc;
        cipher->encrypt(output + posn, test->plaintext + posn, len);
    }
    if (memcmp(output, test->ciphertext, test->size) != 0) {
        Serial.print(output[0], HEX);
        Serial.print("->");
        Serial.print(test->ciphertext[0], HEX);
        return false;
    }
    cipher->setKey(test->key, test->keySize);
    cipher->setIV(test->iv, cipher->ivSize());
    cipher->setCounter(test->counter, 8);
    for (posn = 0; posn < test->size; posn += inc) {
        len = test->size - posn;
        if (len > inc)
            len = inc;
        cipher->decrypt(output + posn, test->ciphertext + posn, len);
    }
    if (memcmp(output, test->plaintext, test->size) != 0)
        return false;
    return true;
}
void testCipher(ChaCha *cipher, const struct TestVector *test)
{
    bool ok;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" ... ");
    cipher->setNumRounds(test->rounds);
    ok  = testCipher_N(cipher, test, test->size);
    ok &= testCipher_N(cipher, test, 1);
    ok &= testCipher_N(cipher, test, 2);
    ok &= testCipher_N(cipher, test, 5);
    ok &= testCipher_N(cipher, test, 8);
    ok &= testCipher_N(cipher, test, 13);
    ok &= testCipher_N(cipher, test, 16);
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfCipherSetKey(ChaCha *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" SetKey ... ");
    cipher->setNumRounds(test->rounds);
    start = micros();
    for (count = 0; count < 1000; ++count) {
        cipher->setKey(test->key, test->keySize);
        cipher->setIV(test->iv, 8);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per operation, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
}
void perfCipherEncrypt(ChaCha *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" Encrypt ... ");
    cipher->setNumRounds(test->rounds);
    cipher->setKey(test->key, test->keySize);
    cipher->setIV(test->iv, cipher->ivSize());
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->encrypt(buffer, buffer, sizeof(buffer));
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (sizeof(buffer) * 500.0));
    Serial.print("us per byte, ");
    Serial.print((sizeof(buffer) * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
void perfCipherDecrypt(ChaCha *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" Decrypt ... ");
    cipher->setNumRounds(test->rounds);
    cipher->setKey(test->key, test->keySize);
    cipher->setIV(test->iv, cipher->ivSize());
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->decrypt(buffer, buffer, sizeof(buffer));
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (sizeof(buffer) * 500.0));
    Serial.print("us per byte, ");
    Serial.print((sizeof(buffer) * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
void perfCipher(ChaCha *cipher, const struct TestVector *test)
{
    perfCipherSetKey(cipher, test);
    perfCipherEncrypt(cipher, test);
    perfCipherDecrypt(cipher, test);
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.print("State Size ...");
    Serial.println(sizeof(ChaCha));
    Serial.println();
    Serial.println("Test Vectors:");
    testCipher(&chacha, &testVectorChaCha20_128);
    testCipher(&chacha, &testVectorChaCha20_256);
    testCipher(&chacha, &testVectorChaCha12_128);
    testCipher(&chacha, &testVectorChaCha12_256);
    testCipher(&chacha, &testVectorChaCha8_128);
    testCipher(&chacha, &testVectorChaCha8_256);
    Serial.println();
    Serial.println("Performance Tests:");
    perfCipher(&chacha, &testVectorChaCha20_128);
    perfCipher(&chacha, &testVectorChaCha20_256);
    perfCipher(&chacha, &testVectorChaCha12_128);
    perfCipher(&chacha, &testVectorChaCha12_256);
    perfCipher(&chacha, &testVectorChaCha8_128);
    perfCipher(&chacha, &testVectorChaCha8_256);
}
void loop()
{
}
src/modules/Crypto/examples/TestChaChaPoly/TestChaChaPoly.ino
New file
@@ -0,0 +1,452 @@
/*
 * 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.
 */
/*
This example runs tests on the ChaChaPoly implementation to verify
correct behaviour.
*/
#include <Crypto.h>
#include <ChaChaPoly.h>
#include <string.h>
#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
#define MAX_PLAINTEXT_LEN 265
struct TestVector
{
    const char *name;
    uint8_t key[32];
    uint8_t plaintext[MAX_PLAINTEXT_LEN];
    uint8_t ciphertext[MAX_PLAINTEXT_LEN];
    uint8_t authdata[16];
    uint8_t iv[16];
    uint8_t tag[16];
    size_t authsize;
    size_t datasize;
    size_t tagsize;
    size_t ivsize;
};
// Test vectors for ChaChaPoly from draft-nir-cfrg-chacha20-poly1305-04.txt
static TestVector const testVectorChaChaPoly_1 PROGMEM = {
    .name        = "ChaChaPoly #1",
    .key         = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
                    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
                    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
                    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f},
    .plaintext   = {0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
                    0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
                    0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
                    0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
                    0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
                    0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
                    0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
                    0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
                    0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
                    0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
                    0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
                    0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
                    0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
                    0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
                    0x74, 0x2e},
    .ciphertext  = {0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
                    0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
                    0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
                    0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
                    0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
                    0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
                    0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
                    0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
                    0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
                    0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
                    0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
                    0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
                    0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
                    0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
                    0x61, 0x16},
    .authdata    = {0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
                    0xc4, 0xc5, 0xc6, 0xc7},
    .iv          = {0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
                    0x44, 0x45, 0x46, 0x47},
    .tag         = {0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
                    0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91},
    .authsize    = 12,
    .datasize    = 114,
    .tagsize     = 16,
    .ivsize      = 12
};
static TestVector const testVectorChaChaPoly_2 PROGMEM = {
    .name        = "ChaChaPoly #2",
    .key         = {0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
                    0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
                    0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
                    0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0},
    .plaintext   = {0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
                    0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20,
                    0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
                    0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
                    0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69,
                    0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
                    0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20,
                    0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d,
                    0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
                    0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
                    0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
                    0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
                    0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
                    0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64,
                    0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
                    0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
                    0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61,
                    0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
                    0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69,
                    0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72,
                    0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
                    0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65,
                    0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
                    0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
                    0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
                    0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
                    0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
                    0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
                    0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
                    0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
                    0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b,
                    0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67,
                    0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
                    0x9d},
    .ciphertext  = {0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4,
                    0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd,
                    0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
                    0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2,
                    0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee,
                    0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
                    0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00,
                    0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf,
                    0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
                    0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81,
                    0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd,
                    0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
                    0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61,
                    0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38,
                    0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
                    0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4,
                    0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46,
                    0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
                    0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e,
                    0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e,
                    0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
                    0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a,
                    0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea,
                    0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
                    0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99,
                    0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e,
                    0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
                    0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10,
                    0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94,
                    0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
                    0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf,
                    0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29,
                    0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
                    0x9b},
    .authdata    = {0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x4e, 0x91},
    .iv          = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
    .tag         = {0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22,
                    0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, 0x38},
    .authsize    = 12,
    .datasize    = 265,
    .tagsize     = 16,
    .ivsize      = 8
};
TestVector testVector;
ChaChaPoly chachapoly;
byte buffer[MAX_PLAINTEXT_LEN];
bool testCipher_N(ChaChaPoly *cipher, const struct TestVector *test, size_t inc)
{
    size_t posn, len;
    uint8_t tag[16];
    cipher->clear();
    if (!cipher->setKey(test->key, 32)) {
        Serial.print("setKey ");
        return false;
    }
    if (!cipher->setIV(test->iv, test->ivsize)) {
        Serial.print("setIV ");
        return false;
    }
    memset(buffer, 0xBA, sizeof(buffer));
    for (posn = 0; posn < test->authsize; posn += inc) {
        len = test->authsize - posn;
        if (len > inc)
            len = inc;
        cipher->addAuthData(test->authdata + posn, len);
    }
    for (posn = 0; posn < test->datasize; posn += inc) {
        len = test->datasize - posn;
        if (len > inc)
            len = inc;
        cipher->encrypt(buffer + posn, test->plaintext + posn, len);
    }
    if (memcmp(buffer, test->ciphertext, test->datasize) != 0) {
        Serial.print(buffer[0], HEX);
        Serial.print("->");
        Serial.print(test->ciphertext[0], HEX);
        return false;
    }
    cipher->computeTag(tag, sizeof(tag));
    if (memcmp(tag, test->tag, sizeof(tag)) != 0) {
        Serial.print("computed wrong tag ... ");
        return false;
    }
    cipher->setKey(test->key, 32);
    cipher->setIV(test->iv, test->ivsize);
    for (posn = 0; posn < test->authsize; posn += inc) {
        len = test->authsize - posn;
        if (len > inc)
            len = inc;
        cipher->addAuthData(test->authdata + posn, len);
    }
    for (posn = 0; posn < test->datasize; posn += inc) {
        len = test->datasize - posn;
        if (len > inc)
            len = inc;
        cipher->decrypt(buffer + posn, test->ciphertext + posn, len);
    }
    if (memcmp(buffer, test->plaintext, test->datasize) != 0)
        return false;
    if (!cipher->checkTag(tag, sizeof(tag))) {
        Serial.print("tag did not check ... ");
        return false;
    }
    return true;
}
void testCipher(ChaChaPoly *cipher, const struct TestVector *test)
{
    bool ok;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" ... ");
    ok  = testCipher_N(cipher, test, test->datasize);
    ok &= testCipher_N(cipher, test, 1);
    ok &= testCipher_N(cipher, test, 2);
    ok &= testCipher_N(cipher, test, 5);
    ok &= testCipher_N(cipher, test, 8);
    ok &= testCipher_N(cipher, test, 13);
    ok &= testCipher_N(cipher, test, 16);
    if (ok)
        Serial.println("Passed");
    else
        Serial.println("Failed");
}
void perfCipherSetKey(ChaChaPoly *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" SetKey ... ");
    start = micros();
    for (count = 0; count < 1000; ++count) {
        cipher->setKey(test->key, 32);
        cipher->setIV(test->iv, test->ivsize);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per operation, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
}
void perfCipherEncrypt(ChaChaPoly *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" Encrypt ... ");
    cipher->setKey(test->key, 32);
    cipher->setIV(test->iv, test->ivsize);
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->encrypt(buffer, buffer, 128);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (128.0 * 500.0));
    Serial.print("us per byte, ");
    Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
void perfCipherDecrypt(ChaChaPoly *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" Decrypt ... ");
    cipher->setKey(test->key, 32);
    cipher->setIV(test->iv, test->ivsize);
    start = micros();
    for (count = 0; count < 500; ++count) {
        cipher->decrypt(buffer, buffer, 128);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (128.0 * 500.0));
    Serial.print("us per byte, ");
    Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
void perfCipherAddAuthData(ChaChaPoly *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" AddAuthData ... ");
    cipher->setKey(test->key, 32);
    cipher->setIV(test->iv, test->ivsize);
    start = micros();
    memset(buffer, 0xBA, 128);
    for (count = 0; count < 500; ++count) {
        cipher->addAuthData(buffer, 128);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / (128.0 * 500.0));
    Serial.print("us per byte, ");
    Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
    Serial.println(" bytes per second");
}
/*
void perfCipherComputeTag(ChaChaPoly *cipher, const struct TestVector *test)
{
    unsigned long start;
    unsigned long elapsed;
    int count;
    memcpy_P(&testVector, test, sizeof(TestVector));
    test = &testVector;
    Serial.print(test->name);
    Serial.print(" ComputeTag ... ");
    cipher->setKey(test->key, 32);
    cipher->setIV(test->iv, test->ivsize);
    start = micros();
    for (count = 0; count < 1000; ++count) {
        cipher->computeTag(buffer, 16);
    }
    elapsed = micros() - start;
    Serial.print(elapsed / 1000.0);
    Serial.print("us per operation, ");
    Serial.print((1000.0 * 1000000.0) / elapsed);
    Serial.println(" per second");
}
*/
void perfCipher(ChaChaPoly *cipher, const struct TestVector *test)
{
    perfCipherSetKey(cipher, test);
    perfCipherEncrypt(cipher, test);
    perfCipherDecrypt(cipher, test);
    perfCipherAddAuthData(cipher, test);
    //perfCipherComputeTag(cipher, test);
}
void setup()
{
    Serial.begin(9600);
    Serial.println();
    Serial.print("State Size ... ");
    Serial.println(sizeof(ChaChaPoly));
    Serial.println();
    Serial.println("Test Vectors:");
    testCipher(&chachapoly, &testVectorChaChaPoly_1);
    testCipher(&chachapoly, &testVectorChaChaPoly_2);
    Serial.println();
    Serial.println("Performance Tests:");
    perfCipher(&chachapoly, &testVectorChaChaPoly_1);
}
void loop()
{
}
src/modules/Crypto/examples/TestCurve25519/TestCurve25519.ino
New file
@@ -0,0 +1,221 @@
/*
 * 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.
 */
/*
This example runs tests on the Curve25519 algorithm.
*/
#include <Crypto.h>
#include <Curve25519.h>
#include <RNG.h>
#include <string.h>
void printNumber(const char *name, const uint8_t *x)
{
    static const char hexchars[] = "0123456789ABCDEF";
    Serial.print(name);
    Serial.print(" = ");
    for (uint8_t posn = 0; posn < 32; ++posn) {
        Serial.print(hexchars[(x[posn] >> 4) & 0x0F]);
        Serial.print(hexchars[x[posn] & 0x0F]);
    }
    Serial.println();
}
// Check the eval() function using the test vectors from
// section 6.1 of RFC 7748.
void testEval()
{
    static uint8_t alice_private[32] = {
        0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d,
        0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
        0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
        0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a
    };
    static uint8_t const alice_public[32] = {
        0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54,
        0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a,
        0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4,
        0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a
    };
    static uint8_t bob_private[32] = {
        0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b,
        0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6,
        0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd,
        0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb
    };
    static uint8_t const bob_public[32] = {
        0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4,
        0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37,
        0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d,
        0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f
    };
    static uint8_t const shared_secret[32] = {
        0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1,
        0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25,
        0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
        0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42
    };
    // Fix up the private keys by applying the standard masks.
    alice_private[0] &= 0xF8;
    alice_private[31] = (alice_private[31] & 0x7F) | 0x40;
    bob_private[0] &= 0xF8;
    bob_private[31] = (bob_private[31] & 0x7F) | 0x40;
    // Evaluate the curve function and check the public keys.
    uint8_t result[32];
    Serial.println("Fixed test vectors:");
    Serial.print("Computing Alice's public key ... ");
    Serial.flush();
    unsigned long start = micros();
    Curve25519::eval(result, alice_private, 0);
    unsigned long elapsed = micros() - start;
    if (memcmp(result, alice_public, 32) == 0) {
        Serial.print("ok");
    } else {
        Serial.println("failed");
        printNumber("actual  ", result);
        printNumber("expected", alice_public);
    }
    Serial.print(" (elapsed ");
    Serial.print(elapsed);
    Serial.println(" us)");
    Serial.print("Computing Bob's public key ... ");
    Serial.flush();
    start = micros();
    Curve25519::eval(result, bob_private, 0);
    elapsed = micros() - start;
    if (memcmp(result, bob_public, 32) == 0) {
        Serial.print("ok");
    } else {
        Serial.println("failed");
        printNumber("actual  ", result);
        printNumber("expected", bob_public);
    }
    Serial.print(" (elapsed ");
    Serial.print(elapsed);
    Serial.println(" us)");
    // Compute the shared secret from each side.
    Serial.print("Computing Alice's shared secret ... ");
    Serial.flush();
    start = micros();
    Curve25519::eval(result, alice_private, bob_public);
    elapsed = micros() - start;
    if (memcmp(result, shared_secret, 32) == 0) {
        Serial.print("ok");
    } else {
        Serial.println("failed");
        printNumber("actual  ", result);
        printNumber("expected", shared_secret);
    }
    Serial.print(" (elapsed ");
    Serial.print(elapsed);
    Serial.println(" us)");
    Serial.print("Computing Bob's shared secret ... ");
    Serial.flush();
    start = micros();
    Curve25519::eval(result, bob_private, alice_public);
    elapsed = micros() - start;
    if (memcmp(result, shared_secret, 32) == 0) {
        Serial.print("ok");
    } else {
        Serial.println("failed");
        printNumber("actual  ", result);
        printNumber("expected", shared_secret);
    }
    Serial.print(" (elapsed ");
    Serial.print(elapsed);
    Serial.println(" us)");
}
void testDH()
{
    static uint8_t alice_k[32];
    static uint8_t alice_f[32];
    static uint8_t bob_k[32];
    static uint8_t bob_f[32];
    Serial.println("Diffie-Hellman key exchange:");
    Serial.print("Generate random k/f for Alice ... ");
    Serial.flush();
    unsigned long start = micros();
    Curve25519::dh1(alice_k, alice_f);
    unsigned long elapsed = micros() - start;
    Serial.print("elapsed ");
    Serial.print(elapsed);
    Serial.println(" us");
    Serial.print("Generate random k/f for Bob ... ");
    Serial.flush();
    start = micros();
    Curve25519::dh1(bob_k, bob_f);
    elapsed = micros() - start;
    Serial.print("elapsed ");
    Serial.print(elapsed);
    Serial.println(" us");
    Serial.print("Generate shared secret for Alice ... ");
    Serial.flush();
    start = micros();
    Curve25519::dh2(bob_k, alice_f);
    elapsed = micros() - start;
    Serial.print("elapsed ");
    Serial.print(elapsed);
    Serial.println(" us");
    Serial.print("Generate shared secret for Bob ... ");
    Serial.flush();
    start = micros();
    Curve25519::dh2(alice_k, bob_f);
    elapsed = micros() - start;
    Serial.print("elapsed ");
    Serial.print(elapsed);
    Serial.println(" us");
    Serial.print("Check that the shared secrets match ... ");
    if (memcmp(alice_k, bob_k, 32) == 0)
        Serial.println("ok");
    else
        Serial.println("failed");
}
void setup()
{
    Serial.begin(9600);
    // Start the random number generator.  We don't initialise a noise
    // source here because we don't need one for testing purposes.
    // Real DH applications should of course use a proper noise source.
    RNG.begin("TestCurve25519 1.0");
    // Perform the tests.
    testEval();
    Serial.println();
    testDH();
    Serial.println();
}
void loop()
{
}
Diff truncated after the above file
src/modules/Crypto/examples/TestCurve25519Math/TestCurve25519Math.ino src/modules/Crypto/examples/TestEAX/TestEAX.ino src/modules/Crypto/examples/TestEd25519/TestEd25519.ino src/modules/Crypto/examples/TestGCM/TestGCM.ino src/modules/Crypto/examples/TestGHASH/TestGHASH.ino src/modules/Crypto/examples/TestP521/TestP521.ino src/modules/Crypto/examples/TestP521Math/TestP521Math.ino src/modules/Crypto/examples/TestPoly1305/TestPoly1305.ino src/modules/Crypto/examples/TestRNG/TestRNG.ino src/modules/Crypto/examples/TestSHA256/TestSHA256.ino src/modules/Crypto/examples/TestSHA3_256/TestSHA3_256.ino src/modules/Crypto/examples/TestSHA3_512/TestSHA3_512.ino src/modules/Crypto/examples/TestSHA512/TestSHA512.ino src/modules/Crypto/examples/TestSHAKE128/TestSHAKE128.ino src/modules/Crypto/examples/TestSHAKE256/TestSHAKE256.ino src/modules/Crypto/examples/TestXTS/TestXTS.ino src/modules/Crypto/keywords.txt src/modules/Crypto/library.json src/modules/Crypto/utility/EndianUtil.h src/modules/Crypto/utility/LimbUtil.h src/modules/Crypto/utility/ProgMemUtil.h src/modules/Crypto/utility/RotateUtil.h src/modules/mqtt/PubSubClient.cpp src/modules/mqtt/PubSubClient.h