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