ni.ha (2343B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use crypto::cipher; 5 use rt; 6 7 def EXPKEYLEN128: size = 176; 8 def EXPKEYLEN192: size = 208; 9 def EXPKEYLEN256: size = 240; 10 11 def X86NI_EXPKEYSZ: size = 480; 12 13 const x86ni_vtable: cipher::blockvtable = cipher::blockvtable { 14 blocksz = BLOCKSZ, 15 nparallel = 1, 16 encrypt = &x86ni_encrypt, 17 decrypt = &x86ni_decrypt, 18 finish = &block_finish, 19 }; 20 21 // Checks if the native AES interface is available. 22 fn x86ni_available() bool = { 23 return rt::cpuid_hasflags(0, rt::cpuid_ecxflag::AES | rt::cpuid_ecxflag::AVX); 24 }; 25 26 // Returns a native AES [[crypto::cipher::block]] implementation for x86_64 27 // CPUs supporting AES-NI. 28 // 29 // The caller must call [[x86ni_init]] to add a key to the cipher before using 30 // the cipher, and must call [[crypto::cipher::finish]] when they are finished 31 // using the cipher to securely erase any secret data stored in the cipher 32 // state. 33 fn x86ni() block = { 34 return block { 35 vtable = &x86ni_vtable, 36 ... 37 }; 38 }; 39 40 fn x86ni_init(b: *block, key: []u8) void = { 41 assert(len(key) == 16 || len(key) == 24 || len(key) == 32, 42 "Invalid aes key length"); 43 44 let enc = b.expkey[..EXPKEYLEN256]; 45 let dec = b.expkey[EXPKEYLEN256..]; 46 const expkeylen = x86ni_keyexp(key[..], enc, dec); 47 b.rounds = (expkeylen >> 4) - 1; 48 }; 49 50 fn x86ni_encrypt(b: *cipher::block, dest: []u8, src: []u8) void = { 51 assert(len(dest) == len(src) && len(dest) % BLOCKSZ == 0); 52 let b = b: *block; 53 const expkeylen = (b.rounds + 1) << 4; 54 let enc = b.expkey[..expkeylen]; 55 56 // XXX loop could be done in assembly 57 for (len(src) > 0) { 58 x86ni_asencrypt(enc, dest, src); 59 src = src[BLOCKSZ..]; 60 dest = dest[BLOCKSZ..]; 61 }; 62 }; 63 64 fn x86ni_decrypt(b: *cipher::block, dest: []u8, src: []u8) void = { 65 assert(len(dest) == len(src) && len(dest) % BLOCKSZ == 0); 66 let b = b: *block; 67 const expkeylen = (b.rounds + 1) << 4; 68 let dec = b.expkey[EXPKEYLEN256..]; 69 70 // XXX loop could be done in assembly 71 for (len(src) > 0) { 72 x86ni_asdecrypt(dec[..expkeylen], dest, src); 73 src = src[BLOCKSZ..]; 74 dest = dest[BLOCKSZ..]; 75 }; 76 }; 77 78 // Expands encryption and decryption key and returns the size of the round keys. 79 fn x86ni_keyexp(key: []u8, enc_rk: []u8, dec_rk: []u8) u8; 80 fn x86ni_asencrypt(key_exp: []u8, dest: []u8, src: []u8) void; 81 fn x86ni_asdecrypt(key_exp: []u8, dest: []u8, src: []u8) void;