hare

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

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;