Skip to content

Instantly share code, notes, and snippets.

@ptone
Created December 27, 2018 19:13
Show Gist options
  • Save ptone/a7d29fa756b42bd2256fa28944cc2b1c to your computer and use it in GitHub Desktop.
Save ptone/a7d29fa756b42bd2256fa28944cc2b1c to your computer and use it in GitHub Desktop.
chachapoly interop sanity check
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
data = b"secret"
data = bytes([0x01,0x01,0x01,0x01,0x01,0x01])
aad = b"1111111111111111"
aad = bytes([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01])
nonce = b"111111111111" # os.urandom(12)
nonce = bytes([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01])
test_key = ChaCha20Poly1305.generate_key()
key = bytes([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38])
chacha = ChaCha20Poly1305(key)
# nonce = os.urandom(12)
ct = chacha.encrypt(nonce, data, aad)
v = chacha.decrypt(nonce, ct, aad)
print(v)
print(len(ct))
print(" ".join("{:02x}".format(x) for x in ct))
#include <Arduino.h>
#include <Crypto.h>
#include <ChaChaPoly.h> // https://rweather.github.io/arduinolibs/classChaChaPoly.html
#include <Base64.h>
#include <rBase64.h>
#define CHA_CHA_POLY_KEY_SIZE 32
#define CHA_CHA_POLY_IV_SIZE 12
#define CHA_CHA_POLY_AUTH_SIZE 16
#define CHA_CHA_POLY_TAG_SIZE 16
#define CHA_CHA_POLY_MESSAGE_SIZE 6
ChaChaPoly chachapoly;
void encrypt(const byte key[CHA_CHA_POLY_KEY_SIZE], const byte iv[CHA_CHA_POLY_IV_SIZE], const byte auth[CHA_CHA_POLY_AUTH_SIZE], const byte plainText[CHA_CHA_POLY_MESSAGE_SIZE], byte cipherText[CHA_CHA_POLY_MESSAGE_SIZE], byte tag[CHA_CHA_POLY_TAG_SIZE])
{
chachapoly.clear();
chachapoly.setKey(key, CHA_CHA_POLY_KEY_SIZE);
chachapoly.setIV(iv, CHA_CHA_POLY_IV_SIZE);
chachapoly.addAuthData(auth, CHA_CHA_POLY_AUTH_SIZE);
chachapoly.encrypt(cipherText, plainText, CHA_CHA_POLY_MESSAGE_SIZE);
chachapoly.computeTag(tag, CHA_CHA_POLY_TAG_SIZE);
}
bool decrypt(const byte key[CHA_CHA_POLY_KEY_SIZE], const byte iv[CHA_CHA_POLY_IV_SIZE], const byte auth[CHA_CHA_POLY_AUTH_SIZE], const byte cipherText[CHA_CHA_POLY_MESSAGE_SIZE], byte plainText[CHA_CHA_POLY_MESSAGE_SIZE], const byte tag[CHA_CHA_POLY_TAG_SIZE])
{
chachapoly.clear();
chachapoly.setKey(key, CHA_CHA_POLY_KEY_SIZE);
chachapoly.setIV(iv, CHA_CHA_POLY_IV_SIZE);
chachapoly.addAuthData(auth, CHA_CHA_POLY_AUTH_SIZE);
chachapoly.decrypt(plainText, cipherText, CHA_CHA_POLY_MESSAGE_SIZE);
return chachapoly.checkTag(tag, CHA_CHA_POLY_TAG_SIZE);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(1500);
Serial.print("Testing ecc\n");
byte key[CHA_CHA_POLY_KEY_SIZE] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38};
byte iv[CHA_CHA_POLY_IV_SIZE] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
// construct plain text message
byte plainText[CHA_CHA_POLY_MESSAGE_SIZE] = {0x01,0x01,0x01,0x01,0x01,0x01};
byte decrypted[CHA_CHA_POLY_MESSAGE_SIZE];
// String plain = "secret";
// plain.getBytes(plainText, CHA_CHA_POLY_MESSAGE_SIZE);
// Serial.print("got bytes \n");
// set additional auth data
byte aad[16] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
byte cipherText[CHA_CHA_POLY_MESSAGE_SIZE];
byte tag[CHA_CHA_POLY_TAG_SIZE];
encrypt(key, iv, aad, plainText, cipherText, tag);
Serial.println("plain");
Serial.println(sizeof(plainText));
for (int i=0; i<CHA_CHA_POLY_MESSAGE_SIZE; i++) {
Serial.print(" ");
Serial.print(plainText[i], HEX);
}
Serial.println();
Serial.println();
Serial.println("encrypted");
Serial.println(sizeof(cipherText));
for (int i=0; i<CHA_CHA_POLY_MESSAGE_SIZE; i++) {
Serial.print(" ");
Serial.print(cipherText[i], HEX);
}
Serial.println();
Serial.println();
Serial.println("tag");
Serial.println(sizeof(tag));
for (int i=0; i<CHA_CHA_POLY_TAG_SIZE; i++) {
Serial.print(" ");
Serial.print(tag[i], HEX);
}
Serial.println();
Serial.println();
// base64 encoding
Serial.println("encoding: ");
int inputStringLength = sizeof(cipherText);
int encodedLength = Base64.encodedLength(inputStringLength);
char encodedString[encodedLength];
// this line was key and eluded me for a long time
char* cipherchar = reinterpret_cast<char*>(cipherText);
Base64.encode(encodedString, cipherchar, inputStringLength);
Serial.print("Encoded string is:\n");
Serial.println(encodedString);
if (rbase64.encode(cipherchar) == RBASE64_STATUS_OK) {
Serial.println("\nConverted the String to Base64 : ");
Serial.println(rbase64.result());
Serial.println(strlen(cipherchar));
}
// decrypt message from cipherText to plainText
// output is valid only if result is true
bool result = decrypt(key, iv, aad, cipherText, decrypted, tag);
if (result) {
Serial.println("decrypt ok:");
// String dmsg = (char*)decrypted;
// Serial.println(dmsg);
for (int i=0; i<CHA_CHA_POLY_MESSAGE_SIZE; i++) {
// Serial.print(", 0x");
Serial.print(" ");
Serial.print(decrypted[i], HEX);
}
} else {
Serial.println("decrypt failed in some way");
}
}
void loop() {
// put your main code here, to run repeatedly:
}
var chacha = require('chacha');
// https://github.com/calvinmetcalf/chacha20poly1305
const key = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38]);
const nonce = Buffer.from([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01])
const aad = Buffer.from([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01])
const secret = Buffer.from([0x01,0x01,0x01,0x01,0x01,0x01])
var cipher = chacha.createCipher(key, nonce);
cipher.setAAD(aad);
const ciphertext = cipher.update(secret);
cipher.final();
var tag = cipher.getAuthTag();// must be called after finish or end
console.log(ciphertext);
console.log(tag);
var decipher = chacha.createDecipher(key, nonce);
package main
import (
"encoding/base64"
"fmt"
"log"
"golang.org/x/crypto/chacha20poly1305"
)
//using 8byte nonce
// var enc = "NJ3ENqqtKtWkKplMmNhW6xeEj6gID5B1fILh9JVT5JnyT7D4S1bC4uHGXr4un6KgbDg7BYDDdMI2eykr"
// using 12 byte nonce
// var enc = "ej0sf8MpWNw+9532JJFhSbRK8QXDLzYI8aqymboTdVOF1T6nXtel/A3PbpvSLAKP+qhENx6OCrjlWd2c"
var enc = "ej0lYsMpWNw+9532JJFhSbRK8QXDL9+i3Wtv21DgQ3awx7EGUxaWSNgZGxofXDSewVbpTA6OCrgUpiJj"
var key = []byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
// byte auth[CHA_CHA_POLY_AUTH_SIZE] = {
// 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
// 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};
// var iv = []byte{1, 1, 1, 1, 1, 1, 1, 1}
var iv = []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
var aad = []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
func reverse(numbers []byte) []byte {
for i := 0; i < len(numbers)/2; i++ {
j := len(numbers) - i - 1
numbers[i], numbers[j] = numbers[j], numbers[i]
}
return numbers
}
func main() {
ciphertext, err := base64.StdEncoding.DecodeString(enc)
if err != nil {
log.Fatal("decode failed")
}
// log.Println(ciphertext)
// var key2 []byte
// key2 = reverse(key)
chacha, err := chacha20poly1305.New(key)
if err != nil {
log.Fatal("chacha init failed")
}
// Decryption.
plaintext, err := chacha.Open(nil, iv, ciphertext, aad)
if err != nil {
for _, x := range ciphertext {
// fmt.Printf("%02x ", x)
fmt.Printf("%x ", x)
}
fmt.Println()
fmt.Println(len(ciphertext))
log.Println("Failed to decrypt or authenticate message:", err)
}
fmt.Printf("%s\n", plaintext)
fmt.Println("Part 2")
// plain2 := []byte("secret")
plain2 := []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01}
chacha2, err := chacha20poly1305.New(key)
cipher2 := chacha2.Seal(nil, iv, plain2, aad)
plain2opened, err := chacha2.Open(nil, iv, cipher2, aad)
if err != nil {
for _, x := range cipher2 {
// fmt.Printf("%02x ", x)
fmt.Printf("%x ", x)
}
fmt.Println()
fmt.Println(len(cipher2))
log.Println("Failed to decrypt or authenticate message:", err)
} else {
fmt.Println("oh boy")
}
fmt.Println(string(plain2opened))
for _, x := range cipher2 {
fmt.Printf("%02x ", x)
// fmt.Printf("%x ", x)
}
fmt.Println()
fmt.Println(len(cipher2))
}
The full payload is ciphertext of 6 bytes + tag of 16 bytes
The AAD extra data is included in tag, but not in ciphertext - it acts as a second verification factor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment