Upload files to "/"
This commit is contained in:
198
aead.d
Normal file
198
aead.d
Normal file
@@ -0,0 +1,198 @@
|
||||
module angel.utils.cryptography.aead;
|
||||
|
||||
public import angel.utils.cryptography.blockcipher;
|
||||
|
||||
///
|
||||
/// Test if T is a AEAD cipher.
|
||||
///
|
||||
@safe
|
||||
template isAEADCipher(T)
|
||||
{
|
||||
enum bool isAEADCipher =
|
||||
is(T == struct) &&
|
||||
is(typeof(
|
||||
{
|
||||
ubyte[0] block;
|
||||
T bc = void; //Can define
|
||||
|
||||
bc.start(true, block, block); // start with key, iv
|
||||
|
||||
string name = T.name;
|
||||
uint macSize = T.macSize;
|
||||
|
||||
//BlockCipher c = bc.getUnderlyingCipher();
|
||||
bc.processAADBytes(cast (const ubyte[])block);
|
||||
|
||||
ubyte[] slice = bc.processBytes(cast(const ubyte[]) [0], cast(ubyte[]) [0]);
|
||||
//ubyte[] mac = bc.finish(block);
|
||||
|
||||
size_t len = bc.finish(cast(ubyte[]) [0], cast(ubyte[]) [0]);
|
||||
size_t s1 = bc.getUpdateOutputSize(cast(size_t) 0);
|
||||
size_t s2 = bc.getOutputSize(cast(size_t) 0);
|
||||
}));
|
||||
}
|
||||
|
||||
@safe
|
||||
public interface IAEADEngine
|
||||
{
|
||||
|
||||
public {
|
||||
|
||||
/// Initialize the underlying cipher.
|
||||
/// Params:
|
||||
/// forEncryption = true if we are setting up for encryption, false otherwise.
|
||||
/// key = Secret key.
|
||||
/// nonce = Number used only once.
|
||||
void start(in ubyte[] key, in ubyte[] nonce) nothrow @nogc;
|
||||
|
||||
/// Returns: Returns the name of the algorithm.
|
||||
@property
|
||||
string name() pure nothrow;
|
||||
|
||||
|
||||
/// Process additional authenticated data.
|
||||
void processAADBytes(in ubyte[] aad) nothrow;
|
||||
|
||||
/// Encrypt or decrypt a block of bytes.
|
||||
///
|
||||
/// Params:
|
||||
/// input = Input buffer.
|
||||
/// output = Output buffer.
|
||||
///
|
||||
/// Returns: A slice pointing to the output data.
|
||||
ubyte[] processBytes(in ubyte[] input, ubyte[] output) nothrow;
|
||||
|
||||
/// Close the AEAD cipher by producing the remaining output and a authentication tag.
|
||||
///
|
||||
/// Params:
|
||||
/// macBuf = Buffer for the MAC tag.
|
||||
/// output = Buffer for remaining output data.
|
||||
///
|
||||
/// Note: In decryption mode this does not verify the integrity of the data. Verification has to be done by the programmer!
|
||||
///
|
||||
size_t finish(ubyte[] macBuf, ubyte[] output);
|
||||
|
||||
/// Returns: Return the size of the output buffer required for a processBytes an input of len bytes.
|
||||
size_t getUpdateOutputSize(size_t len) nothrow const;
|
||||
|
||||
/// Returns: Return the size of the output buffer required for a processBytes plus a finish with an input of len bytes.
|
||||
size_t getOutputSize(size_t len) nothrow const;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO AEAD cipher wrapper
|
||||
/// Wrapper class for AEAD ciphers
|
||||
@safe
|
||||
public class AEADCipherWrapper(T) if(isAEADCipher!T): IAEADEngine
|
||||
{
|
||||
|
||||
private T cipher;
|
||||
|
||||
public {
|
||||
|
||||
void start(in ubyte[] key, in ubyte[] iv) {
|
||||
cipher.start(key, iv);
|
||||
}
|
||||
|
||||
@property
|
||||
string name() pure nothrow {
|
||||
return cipher.name;
|
||||
}
|
||||
|
||||
void processAADBytes(in ubyte[] aad) nothrow {
|
||||
cipher.processAADBytes(aad);
|
||||
}
|
||||
|
||||
|
||||
ubyte[] processBytes(in ubyte[] input, ubyte[] output) nothrow {
|
||||
return cipher.processBytes(input, output);
|
||||
}
|
||||
|
||||
size_t finish(ubyte[] macBuf, ubyte[] output){
|
||||
return cipher.finish(macBuf, output);
|
||||
}
|
||||
|
||||
size_t getUpdateOutputSize(size_t len) nothrow const {
|
||||
return cipher.getUpdateOutputSize(len);
|
||||
}
|
||||
|
||||
size_t getOutputSize(size_t len) nothrow const {
|
||||
return cipher.getOutputSize(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
version(unittest) {
|
||||
|
||||
// unittest helper functions
|
||||
|
||||
|
||||
/// Runs decryption and encryption using AEADCipher cipher with given keys, plaintexts, and ciphertexts.
|
||||
///
|
||||
/// Params:
|
||||
/// hexKeys = the keys encoded in hex
|
||||
/// hexIVs = hex encoded nonces
|
||||
/// hexPlaintexts = the plaintexts encoded in hex
|
||||
/// hexAAD = additional authenticated data
|
||||
/// hexCiphertexts = the corresponding ciphertexts in hex
|
||||
/// macSize = MAC sizes in bits
|
||||
///
|
||||
/// Throws:
|
||||
/// AssertionError if encryption or decryption failed
|
||||
@safe
|
||||
public void AEADCipherTest(
|
||||
IAEADEngine cipher,
|
||||
in string[] keys,
|
||||
in string[] ivs,
|
||||
in string[] plaintexts,
|
||||
in string[] aads,
|
||||
in string[] ciphertexts,
|
||||
in uint[] macSize
|
||||
) {
|
||||
|
||||
import dcrypt.aead.aead;
|
||||
import std.format: format;
|
||||
|
||||
alias const (ubyte)[] octets;
|
||||
|
||||
foreach (uint i, string test_key; keys)
|
||||
{
|
||||
octets plain = cast(octets) plaintexts[i];
|
||||
octets aad = cast(octets) aads[i];
|
||||
octets ciphertext = cast(octets) ciphertexts[i];
|
||||
|
||||
ubyte[] output = new ubyte[plain.length];
|
||||
|
||||
// set to encryption mode
|
||||
cipher.start(true, cast(octets) test_key, cast(octets) ivs[i]);
|
||||
|
||||
output.length = cipher.getOutputSize(plain.length);
|
||||
|
||||
immutable size_t taglen = macSize[i]/8;
|
||||
octets expectedMac = ciphertext[$-taglen..$];
|
||||
ciphertext = ciphertext[0..$-taglen];
|
||||
|
||||
// assert(cipher.getUpdateOutputSize(plain.length) == plain.length);
|
||||
assert(output.length >= cipher.getUpdateOutputSize(plain.length));
|
||||
|
||||
|
||||
assert(output.length >= cipher.getUpdateOutputSize(plain.length));
|
||||
|
||||
// test encryption
|
||||
cipher.processAADBytes(aad);
|
||||
ubyte[] out_slice = cipher.processBytes(plain, output);
|
||||
|
||||
ubyte[16] mac;
|
||||
size_t len = out_slice.length+cipher.finish(mac, output[out_slice.length..$]);
|
||||
|
||||
assert(output == ciphertext,
|
||||
format("%s encrypt: %(%.2x%) != %(%.2x%)", cipher.name, output, ciphertexts[i]));
|
||||
|
||||
assert(mac[0..taglen] == expectedMac);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user