Initiliazation
This commit is contained in:
373
full/Angel-payload/angel/utils/cryptography/gcm/ghash.d
Normal file
373
full/Angel-payload/angel/utils/cryptography/gcm/ghash.d
Normal file
@@ -0,0 +1,373 @@
|
||||
module angel.utils.cryptography.gcm.ghash;
|
||||
|
||||
import angel.utils.cryptography.gcm.galoisfield;
|
||||
import angel.utils.cryptography.gcm.multiplier;
|
||||
|
||||
// BUG: llvm crashes when using GCMMultiplier64kTable
|
||||
alias GHashGeneral!GCMMultiplier8kTable GHash;
|
||||
|
||||
/// Params:
|
||||
/// Multiplier = a GCM Multiplier like GCMMultiplier8kTable
|
||||
@safe
|
||||
public struct GHashGeneral(Multiplier) if(isGCMMultiplier!Multiplier)
|
||||
{
|
||||
enum BLOCKSIZE = 16; /// block size in bytes
|
||||
|
||||
alias ubyte T;
|
||||
alias T[BLOCKSIZE/(T.sizeof)] block;
|
||||
|
||||
private {
|
||||
|
||||
block stateCipher; /// state for cipher data hashing
|
||||
block H;
|
||||
block stateAAD; /// state for AAD hashing
|
||||
block stateAADPre; /// stateAAD before first cipher byte is processed
|
||||
|
||||
ubyte stateAADOff = 0; /// offset in stateAAD buffer
|
||||
ubyte stateCipherOff = 0; /// offset in stateCipher buffer
|
||||
|
||||
ulong lenAAD = 0; /// length of additional authenticated data (AAD) in bits
|
||||
ulong lenAADPre = 0; /// length of AAD before first cipher byte is processed
|
||||
ulong lenCipher = 0; /// length of authenticated cipher data in bits
|
||||
|
||||
bool aadInput = true; /// AAD or cipher input
|
||||
|
||||
Multiplier gcmMult;
|
||||
}
|
||||
|
||||
invariant {
|
||||
// offsets should never exceed their boundaries
|
||||
assert(stateAADOff <= BLOCKSIZE);
|
||||
assert(stateCipherOff <= BLOCKSIZE);
|
||||
}
|
||||
|
||||
/// Params:
|
||||
/// H = element of GF(2^128)
|
||||
this(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == BLOCKSIZE, "H must be 16 bytes");
|
||||
}
|
||||
body {
|
||||
init(H);
|
||||
}
|
||||
|
||||
/// initialize the hash
|
||||
/// Params:
|
||||
/// H = the factor used for multiplication.
|
||||
public void init(in ubyte[] H) nothrow @nogc
|
||||
in {
|
||||
assert(H.length == BLOCKSIZE, "H must be 16 bytes");
|
||||
}
|
||||
body {
|
||||
this.H[] = H[];
|
||||
|
||||
// init the multiplier
|
||||
gcmMult.init(H);
|
||||
}
|
||||
|
||||
|
||||
/// add data to the AAD stream
|
||||
/// Params:
|
||||
/// aad = data to be authenticated only
|
||||
public void updateAAD(in ubyte[] aad...) nothrow @nogc
|
||||
{
|
||||
update(stateAAD, stateAADOff, aad);
|
||||
lenAAD += aad.length*8;
|
||||
}
|
||||
|
||||
/// Call this before processing any cipher data for better performance.
|
||||
private void finalizeAAD() nothrow @nogc {
|
||||
|
||||
stateCipher[] = stateAAD[];
|
||||
|
||||
if(lenAAD > 0) {
|
||||
stateAADPre[] = stateAAD[];
|
||||
lenAADPre = lenAAD;
|
||||
}
|
||||
|
||||
if(stateAADOff > 0) {
|
||||
// process partial block
|
||||
multiplyH(stateCipher);
|
||||
stateAADOff = 0;
|
||||
}
|
||||
aadInput = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* input = encrypted data
|
||||
*/
|
||||
public void updateCipherData(in ubyte[] input...) nothrow @nogc
|
||||
{
|
||||
if(aadInput) {
|
||||
finalizeAAD(); // sets aadInput = false
|
||||
}
|
||||
update(stateCipher, stateCipherOff, input);
|
||||
lenCipher += input.length*8;
|
||||
}
|
||||
|
||||
/// do final hash round and copy hash to buf
|
||||
/// resets GHASH
|
||||
/// Params: buf = output buffer for hash value
|
||||
public void doFinal(ubyte[] buf) nothrow @nogc
|
||||
in {
|
||||
assert(buf.length >= BLOCKSIZE, "output buffer too short");
|
||||
}
|
||||
body {
|
||||
|
||||
if(stateAADOff > 0) {
|
||||
// process last partial AAD block
|
||||
multiplyH(stateAAD);
|
||||
stateAADOff = 0;
|
||||
}
|
||||
|
||||
// process last incomplete block
|
||||
if(stateCipherOff > 0) {
|
||||
multiplyH(stateCipher);
|
||||
stateCipherOff = 0;
|
||||
}
|
||||
|
||||
if(lenAAD > lenAADPre) {
|
||||
// some AAD has been processed after first cipher bytes arrived
|
||||
// need to adjust the MAC state
|
||||
|
||||
// caluculate the difference
|
||||
stateAADPre[] ^= stateAAD[];
|
||||
|
||||
ulong blockDiff = (lenCipher + 127) / 128; // number of cipher data blocks.
|
||||
// + 127 added for rounding up.
|
||||
|
||||
// calculate H^blockDiff
|
||||
ubyte[BLOCKSIZE] expH;
|
||||
expH[] = H[];
|
||||
GF128.power(expH, blockDiff);
|
||||
|
||||
// propagate the difference to the current block
|
||||
GF128.multiply(stateAADPre, expH);
|
||||
|
||||
// add the difference to the current block
|
||||
stateCipher[] ^= stateAADPre[];
|
||||
}
|
||||
|
||||
// Add a block containing the length of both streams: X ^ (len(A)||len(C)) * H
|
||||
foreach(i;0..8) {
|
||||
stateCipher[i] ^= lenAAD >> (56-8*i);
|
||||
stateCipher[i+8] ^= lenCipher >> (56-8*i);
|
||||
}
|
||||
|
||||
multiplyH(stateCipher);
|
||||
|
||||
buf[0..BLOCKSIZE] = stateCipher[];
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/// Reset the internal state.
|
||||
public void reset() nothrow @nogc {
|
||||
stateAAD[] = 0;
|
||||
stateAADOff = 0;
|
||||
stateCipher[] = 0;
|
||||
stateCipherOff = 0;
|
||||
lenCipher = 0;
|
||||
lenAAD = 0;
|
||||
|
||||
lenAADPre = 0;
|
||||
stateAADPre[] = 0;
|
||||
|
||||
aadInput = true;
|
||||
}
|
||||
|
||||
/// xor X with input bytes and do GF multiplication by H if buffer is full
|
||||
/// Params:
|
||||
/// input = incoming data
|
||||
/// state = update this state
|
||||
/// statePos = pointer to the location where the next byte gets written
|
||||
private void update(ubyte[] state, ref ubyte statePos, in ubyte[] input...) nothrow @nogc
|
||||
in {
|
||||
assert(state.length == 16);
|
||||
}
|
||||
body {
|
||||
import std.algorithm: min;
|
||||
|
||||
const(ubyte)[] iBuf = input;
|
||||
|
||||
if(statePos == BLOCKSIZE) {
|
||||
multiplyH(state);
|
||||
statePos = 0;
|
||||
}
|
||||
|
||||
while(iBuf.length > 0) {
|
||||
|
||||
size_t procLen = min(iBuf.length, BLOCKSIZE-statePos);
|
||||
|
||||
state[statePos..statePos+procLen] ^= iBuf[0..procLen];
|
||||
|
||||
statePos += procLen;
|
||||
iBuf = iBuf[procLen..$];
|
||||
|
||||
if(statePos == BLOCKSIZE) {
|
||||
multiplyH(state);
|
||||
statePos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiply x by H, store result in x.
|
||||
private void multiplyH(ubyte[] x) nothrow @nogc {
|
||||
gcmMult.multiply(x);
|
||||
}
|
||||
|
||||
// unittests
|
||||
|
||||
unittest {
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"66e94bd4ef8a2c3b884cfa59ca342b2e");
|
||||
|
||||
ubyte[16] token;
|
||||
gHash.doFinal(token);
|
||||
|
||||
const(ubyte)[] EK0 = cast(const(ubyte)[])x"58e2fccefa7e3061367f1d57a4e7455a";
|
||||
token[] ^= EK0[];
|
||||
|
||||
assert(token == x"58e2fccefa7e3061367f1d57a4e7455a");
|
||||
}
|
||||
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"66e94bd4ef8a2c3b884cfa59ca342b2e");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"0388dace60b6a392f328c2b971b2fe78");
|
||||
|
||||
// check X1
|
||||
assert(gHash.stateCipher == cast(const(ubyte)[])x"5e2ec746917062882c85b0685353deb7");
|
||||
|
||||
ubyte[16] hash;
|
||||
gHash.doFinal(hash);
|
||||
|
||||
assert(hash == x"f38cbb1ad69223dcc3457ae5b6b0f885");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
// section 2.1.1
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"73A23D80121DE2D5A850253FCF43120E");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"D609B1F056637A0D46DF998D88E5222A");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"B2C2846512153524C0895E8108000F10");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"1112131415161718191A1B1C1D1E1F20");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"2122232425262728292A2B2C2D2E2F30");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"313233340001");
|
||||
|
||||
ubyte[16] token;
|
||||
gHash.doFinal(token);
|
||||
|
||||
assert(token == x"1BDA7DB505D8A165264986A703A6920D");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
// section 2.4.1
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"E4E01725D724C1215C7309AD34539257");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"E20106D7CD0DF0761E8DCD3D88E54C2A");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"76D457ED");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"13B4C72B389DC5018E72A171DD85A5D3");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"752274D3A019FBCAED09A425CD9B2E1C");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"9B72EEE7C9DE7D52B3F3");
|
||||
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"2A807BDE4AF8A462D467D2FFA3E1D868");
|
||||
}
|
||||
|
||||
// test vectors from
|
||||
// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||||
// section 2.8.1
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"AE19118C3B704FCE42AE0D15D2C15C7A");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"68F2E77696CE7AE8E2CA4EC588E54D00");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"2E58495C");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"C31F53D99E5687F7365119B832D2AAE7");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"0741D593F1F9E2AB3455779B078EB8FE");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"ACDFEC1F8E3E5277F8180B43361F6512");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"ADB16D2E38548A2C719DBA7228D840");
|
||||
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"5AAA6FD11F06A18BE6E77EF2BC18AF93");
|
||||
}
|
||||
|
||||
/// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
|
||||
/// test case 16
|
||||
unittest {
|
||||
|
||||
// init gHash with H = acbef...
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"acbef20579b4b8ebce889bac8732dad7");
|
||||
|
||||
// process AAD
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"feedfacedeadbeeffeedfacedeadbeef");
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"abaddad2");
|
||||
|
||||
// process cipher data
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"522dc1f099567d07f47f37a32a84427d");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"643a8cdcbfe5c0c97598a2bd2555d1aa");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"8cb08e48590dbb3da7b08b1056828838");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"c5f61e6393ba7a0abcc9f662");
|
||||
|
||||
// get the final hash value
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"8bd0c4d8aacd391e67cca447e8c38f65");
|
||||
}
|
||||
|
||||
// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
|
||||
// test case 16
|
||||
// AAD and cipher data come out of order
|
||||
unittest {
|
||||
|
||||
GHash gHash = GHash(cast(const(ubyte)[])x"acbef20579b4b8ebce889bac8732dad7");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"feedfacedeadbeeffeedfacedeadbeef");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"522dc1f099567d07f47f37a32a84427d");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"643a8cdcbfe5c0c97598a2bd2555d1aa");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"8cb08e48590dbb3da7b08b1056828838");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"c5f61e6393ba7a0abcc9f662");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"abaddad2");
|
||||
|
||||
|
||||
ubyte[16] ghash;
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == cast(const(ubyte)[])x"8bd0c4d8aacd391e67cca447e8c38f65");
|
||||
|
||||
// gHash should now be resetted, so do the same thing again
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"feedfacedeadbeeffeedfacedeadbeef");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"522dc1f099567d07f47f37a32a84427d");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"643a8cdcbfe5c0c97598a2bd2555d1aa");
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"8cb08e48590dbb3da7b08b1056828838");
|
||||
|
||||
gHash.updateAAD(cast(const(ubyte)[])x"abaddad2");
|
||||
|
||||
gHash.updateCipherData(cast(const(ubyte)[])x"c5f61e6393ba7a0abcc9f662");
|
||||
|
||||
gHash.doFinal(ghash);
|
||||
|
||||
assert(ghash == x"8bd0c4d8aacd391e67cca447e8c38f65");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user