210 lines
7.9 KiB
Haxe
210 lines
7.9 KiB
Haxe
package leenkx.network.torrent;
|
|
|
|
import haxe.io.Bytes;
|
|
|
|
class Aegis128x4 {
|
|
static inline var D = 4;
|
|
static inline var RATE = 128;
|
|
|
|
static var C0 = Bytes.ofHex("000101020305080d1522375990e97962");
|
|
static var C1 = Bytes.ofHex("db3d18556dc22ff12011314273b528dd");
|
|
|
|
var v:Bytes;
|
|
var nv:Bytes;
|
|
var t:Bytes;
|
|
var t2:Bytes;
|
|
|
|
public function new(key:Bytes, nonce:Bytes) {
|
|
v = Bytes.alloc(512);
|
|
nv = Bytes.alloc(512);
|
|
t = Bytes.alloc(16);
|
|
t2 = Bytes.alloc(16);
|
|
init(key, nonce);
|
|
}
|
|
|
|
static inline function off(j:Int, i:Int):Int {
|
|
return (j * D + i) * 16;
|
|
}
|
|
|
|
static inline function xtime(x:Int):Int {
|
|
return ((x << 1) ^ ((x >> 7) * 0x1b)) & 0xff;
|
|
}
|
|
|
|
static function xorInto(a:Bytes, ao:Int, b:Bytes, bo:Int, out:Bytes, oo:Int):Void {
|
|
for (k in 0...16) out.set(oo + k, a.get(ao + k) ^ b.get(bo + k));
|
|
}
|
|
|
|
function aesRound(inOff:Int, rk:Bytes, rkOff:Int, out:Bytes, outOff:Int):Void {
|
|
for (c in 0...4) for (r in 0...4)
|
|
t2.set(4 * c + r, SBOX[v.get(inOff + 4 * ((c + r) & 3) + r)]);
|
|
for (c in 0...4) {
|
|
var b0 = t2.get(4 * c);
|
|
var b1 = t2.get(4 * c + 1);
|
|
var b2 = t2.get(4 * c + 2);
|
|
var b3 = t2.get(4 * c + 3);
|
|
out.set(outOff + 4 * c, (xtime(b0) ^ xtime(b1) ^ b1 ^ b2 ^ b3) ^ rk.get(rkOff + 4 * c));
|
|
out.set(outOff + 4 * c + 1, (b0 ^ xtime(b1) ^ xtime(b2) ^ b2 ^ b3) ^ rk.get(rkOff + 4 * c + 1));
|
|
out.set(outOff + 4 * c + 2, (b0 ^ b1 ^ xtime(b2) ^ xtime(b3) ^ b3) ^ rk.get(rkOff + 4 * c + 2));
|
|
out.set(outOff + 4 * c + 3, (xtime(b0) ^ b0 ^ b1 ^ b2 ^ xtime(b3)) ^ rk.get(rkOff + 4 * c + 3));
|
|
}
|
|
}
|
|
|
|
function update(m0:Bytes, m0off:Int, m1:Bytes, m1off:Int):Void {
|
|
for (i in 0...D) {
|
|
xorInto(v, off(0, i), m0, m0off + i * 16, t, 0);
|
|
aesRound(off(7, i), t, 0, nv, off(0, i));
|
|
aesRound(off(0, i), v, off(1, i), nv, off(1, i));
|
|
aesRound(off(1, i), v, off(2, i), nv, off(2, i));
|
|
aesRound(off(2, i), v, off(3, i), nv, off(3, i));
|
|
xorInto(v, off(4, i), m1, m1off + i * 16, t, 0);
|
|
aesRound(off(3, i), t, 0, nv, off(4, i));
|
|
aesRound(off(4, i), v, off(5, i), nv, off(5, i));
|
|
aesRound(off(5, i), v, off(6, i), nv, off(6, i));
|
|
aesRound(off(6, i), v, off(7, i), nv, off(7, i));
|
|
}
|
|
v.blit(0, nv, 0, 512);
|
|
}
|
|
|
|
function init(key:Bytes, nonce:Bytes):Void {
|
|
var kn = Bytes.alloc(16);
|
|
var kc0 = Bytes.alloc(16);
|
|
var kc1 = Bytes.alloc(16);
|
|
for (k in 0...16) {
|
|
kn.set(k, key.get(k) ^ nonce.get(k));
|
|
kc0.set(k, key.get(k) ^ C0.get(k));
|
|
kc1.set(k, key.get(k) ^ C1.get(k));
|
|
}
|
|
for (i in 0...D) {
|
|
v.blit(off(0, i), kn, 0, 16);
|
|
v.blit(off(1, i), C1, 0, 16);
|
|
v.blit(off(2, i), C0, 0, 16);
|
|
v.blit(off(3, i), C1, 0, 16);
|
|
v.blit(off(4, i), kn, 0, 16);
|
|
v.blit(off(5, i), kc0, 0, 16);
|
|
v.blit(off(6, i), kc1, 0, 16);
|
|
v.blit(off(7, i), kc0, 0, 16);
|
|
}
|
|
var m0 = Bytes.alloc(64);
|
|
var m1 = Bytes.alloc(64);
|
|
for (i in 0...D) {
|
|
m0.blit(i * 16, nonce, 0, 16);
|
|
m1.blit(i * 16, key, 0, 16);
|
|
}
|
|
for (r in 0...10) {
|
|
for (i in 0...D) {
|
|
v.set(off(3, i), v.get(off(3, i)) ^ i);
|
|
v.set(off(3, i) + 1, v.get(off(3, i) + 1) ^ (D - 1));
|
|
v.set(off(7, i), v.get(off(7, i)) ^ i);
|
|
v.set(off(7, i) + 1, v.get(off(7, i) + 1) ^ (D - 1));
|
|
}
|
|
update(m0, 0, m1, 0);
|
|
}
|
|
}
|
|
|
|
public function absorb(ai:Bytes, aiOff:Int):Void {
|
|
update(ai, aiOff, ai, aiOff + 64);
|
|
}
|
|
|
|
public function enc(xi:Bytes, xiOff:Int):Bytes {
|
|
var out = Bytes.alloc(RATE);
|
|
for (i in 0...D) {
|
|
for (k in 0...16) {
|
|
var z0 = v.get(off(1, i) + k) ^ v.get(off(6, i) + k)
|
|
^ (v.get(off(2, i) + k) & v.get(off(3, i) + k));
|
|
var z1 = v.get(off(2, i) + k) ^ v.get(off(5, i) + k)
|
|
^ (v.get(off(6, i) + k) & v.get(off(7, i) + k));
|
|
out.set(i * 16 + k, xi.get(xiOff + i * 16 + k) ^ z0);
|
|
out.set(64 + i * 16 + k, xi.get(xiOff + 64 + i * 16 + k) ^ z1);
|
|
}
|
|
}
|
|
update(xi, xiOff, xi, xiOff + 64);
|
|
return out;
|
|
}
|
|
|
|
public function nextBlock():Bytes {
|
|
var out = Bytes.alloc(RATE);
|
|
for (i in 0...D) {
|
|
for (k in 0...16) {
|
|
out.set(i * 16 + k, v.get(off(1, i) + k) ^ v.get(off(6, i) + k)
|
|
^ (v.get(off(2, i) + k) & v.get(off(3, i) + k)));
|
|
out.set(64 + i * 16 + k, v.get(off(2, i) + k) ^ v.get(off(5, i) + k)
|
|
^ (v.get(off(6, i) + k) & v.get(off(7, i) + k)));
|
|
}
|
|
}
|
|
for (i in 0...D) {
|
|
aesRound(off(7, i), v, off(0, i), nv, off(0, i));
|
|
aesRound(off(0, i), v, off(1, i), nv, off(1, i));
|
|
aesRound(off(1, i), v, off(2, i), nv, off(2, i));
|
|
aesRound(off(2, i), v, off(3, i), nv, off(3, i));
|
|
aesRound(off(3, i), v, off(4, i), nv, off(4, i));
|
|
aesRound(off(4, i), v, off(5, i), nv, off(5, i));
|
|
aesRound(off(5, i), v, off(6, i), nv, off(6, i));
|
|
aesRound(off(6, i), v, off(7, i), nv, off(7, i));
|
|
}
|
|
v.blit(0, nv, 0, 512);
|
|
return out;
|
|
}
|
|
|
|
public static function selfTest():Bool {
|
|
var key = Bytes.ofHex("000102030405060708090a0b0c0d0e0f");
|
|
var nonce = Bytes.ofHex("101112131415161718191a1b1c1d1e1f");
|
|
var a = new Aegis128x4(key, nonce);
|
|
var expected = Bytes.ofHex(
|
|
"924eb07635003a37e6c6575ba8ce1929c8b6a5d91475445e936d48e794be0ce2" +
|
|
"fcd37d050e24084befe3bbb219d647602e9f58cfb893a8800220242c373a8b18" +
|
|
"1a1f60c4fab64e5471dc72edfcf6fe6bc1e525ebea2d6375a9edd045dce96381" +
|
|
"97a3e25abd228a44d4a14a6d3fe9185cc2d4cf7f4287a98744645674265d4ca8" +
|
|
"7bb50c534f6ec4780530ff1cce8a16e87b08d57557da0b5ef7b5f7d98b0ba189" +
|
|
"6bfcac34ddb68404821a4d665303cb0fd95626f6dfad1aed7467622c38529932" +
|
|
"af339fd2d50ee45fc47665c647cf6586d0669b39d140f0e118a4a511efe2f95a" +
|
|
"7a94330f35c194fadda2a87e42cdeccc233b640d1f4d56e2757e72c1a9d8ecb1" +
|
|
"9f93737d699ba05c11e94f2b201bef5e61caf387cf7cfd3f8300ac7680ccfd76" +
|
|
"5825a671ecef03b7a9c98a601ae3211587a1fe4d558161a8f4c38731f3223032" +
|
|
"7a5aca78d636c05bbc702b2980196ab6915d868408495d07eb527789f282c575" +
|
|
"d0947bfbc1d3309cdffc9be1503aea628834ea57a15b9fbdc0245464a4b8cbef" +
|
|
"e46f4cf71a95ac45b6f0823e3aba1a868c4ecef682fc44a8eba911b3fc7d99f9" +
|
|
"a4fb61e2c928a2ca760b8772f2ea5f2e3d34ea89da73caa3016c280500a155a3" +
|
|
"85075f0080e9d618e7eb40f57c32d9f7d2ab2b320c6e93b155a3787cb83e5281" +
|
|
"0b3af0250ae36831a1b072e499929bcb5cce4d00329d69f1aae36aa541347512");
|
|
if (expected.compare(a.v) != 0) {
|
|
return false;
|
|
}
|
|
var ad = Bytes.alloc(128);
|
|
for (k in 0...8) ad.set(k, [1, 2, 3, 4][k & 3]);
|
|
a.absorb(ad, 0);
|
|
var msg = Bytes.alloc(128);
|
|
for (k in 0...120) msg.set(k, [4, 5, 6, 7][k & 3]);
|
|
var ct = a.enc(msg, 0);
|
|
var expectedCt = Bytes.ofHex(
|
|
"e836118562f4479c9d35c17356a833114c21f9aa39e4dda5e5c87f4152a00fce" +
|
|
"9a7c38f832eafe8b1c12f8a7cf12a81a1ad8a9c24ba9dedfbdaa586ffea67ddc" +
|
|
"801ea97d9ab4a872f42d0e352e2713dacd609f9442c17517c5a29daf3e2a3fac" +
|
|
"4ff6b1380c4e46df7b086af6ce6bc1ed594b8dd64aed2a7e");
|
|
for (k in 0...120) {
|
|
if (ct.get(k) != expectedCt.get(k)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static var SBOX = [
|
|
0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
|
|
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
|
|
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
|
|
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
|
|
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
|
|
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
|
|
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
|
|
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
|
|
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
|
|
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
|
|
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
|
|
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
|
|
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
|
|
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
|
|
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
|
|
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
|
|
];
|
|
}
|