hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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;