1#if NETCOREAPP3_0_OR_GREATER
5using System.Runtime.InteropServices;
6using System.Runtime.Intrinsics;
7using System.Runtime.Intrinsics.X86;
16 static class CipherBlockChaining_x86
19 const int AESBlockSize = 16;
24 public static bool IsSupported => AESCrypt_x86.IsSupported;
37 [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 public static int DecryptAESCrypt(ReadOnlySpan<byte> from, Span<byte> to, ReadOnlySpan<int> key, Span<byte> rvec,
int length)
40 const int XMM_REG_NUM_KEY_FIRST = 2;
41 const int XMM_REG_NUM_KEY_LAST = 7;
42 const nuint FIRST_NON_REG_KEY_offset = 0x70;
44 var xmm_key_shuf_mask = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(AESCrypt_x86.KeyShuffleMask)).AsByte();
46 Span<Vector128<byte>> xmm_key = stackalloc Vector128<byte>[6];
47 ref Vector128<byte> xmm_key_first =
ref MemoryMarshal.GetReference(xmm_key);
49 for (
int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x10; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
51 xmm_key[as_XMMRegister(rnum)] = AESCrypt_x86.LoadKey(key, (nuint)offset, xmm_key_shuf_mask);
55 ref byte prev_block_cipher_ptr =
ref MemoryMarshal.GetReference(rvec);
63 singleBlock_loopTop_128:
69 var xmm_result = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(from), pos);
70 xmm_result = Sse2.Xor(xmm_result, xmm_key_first);
71 for (
int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
73 xmm_result = Aes.Decrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]);
76 for (var key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xa0; key_offset += 0x10)
78 xmm_result = AesDecKey(xmm_result, key, key_offset);
81 var xmm_temp = AESCrypt_x86.LoadKey(key, 0x00);
82 xmm_result = Aes.DecryptLast(xmm_result, xmm_temp);
83 xmm_temp = Vector128Util.LoadUnsafe(in prev_block_cipher_ptr);
84 xmm_result = Sse2.Xor(xmm_result, xmm_temp);
85 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(to), pos);
86 prev_block_cipher_ptr =
ref Unsafe.Add(
ref MemoryMarshal.GetReference(from), pos);
88 length -= AESBlockSize;
89 goto singleBlock_loopTop_128;
92 Unsafe.CopyBlockUnaligned(
ref MemoryMarshal.GetReference(rvec),
ref prev_block_cipher_ptr, 16);
102 singleBlock_loopTop_192:;
103 xmm_result = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(from), pos);
104 xmm_result = Sse2.Xor(xmm_result, xmm_key_first);
105 for (
int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
107 xmm_result = Aes.Decrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]);
110 for (var key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xc0; key_offset += 0x10)
112 xmm_result = AesDecKey(xmm_result, key, key_offset);
115 xmm_temp = AESCrypt_x86.LoadKey(key, 0x00);
116 xmm_result = Aes.DecryptLast(xmm_result, xmm_temp);
117 xmm_temp = Vector128Util.LoadUnsafe(in prev_block_cipher_ptr);
118 xmm_result = Sse2.Xor(xmm_result, xmm_temp);
119 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(to), pos);
120 prev_block_cipher_ptr =
ref Unsafe.Add(
ref MemoryMarshal.GetReference(from), pos); pos += AESBlockSize;
121 length -= AESBlockSize;
124 goto singleBlock_loopTop_192;
131 singleBlock_loopTop_256:;
132 xmm_result = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(from), pos);
133 xmm_result = Sse2.Xor(xmm_result, xmm_key_first);
134 for (
int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
136 xmm_result = Aes.Decrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]);
139 for (var key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xe0; key_offset += 0x10)
141 xmm_result = AesDecKey(xmm_result, key, key_offset);
144 xmm_temp = AESCrypt_x86.LoadKey(key, 0x00);
145 xmm_result = Aes.DecryptLast(xmm_result, xmm_temp);
146 xmm_temp = Vector128Util.LoadUnsafe(in prev_block_cipher_ptr);
147 xmm_result = Sse2.Xor(xmm_result, xmm_temp);
148 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(to), pos);
149 prev_block_cipher_ptr =
ref Unsafe.Add(
ref MemoryMarshal.GetReference(from), pos); pos += AESBlockSize;
150 length -= AESBlockSize;
153 goto singleBlock_loopTop_256;
170 [MethodImpl(MethodImplOptions.AggressiveInlining)]
171 public static int EncryptAESCrypt(ReadOnlySpan<byte> from, Span<byte> to, ReadOnlySpan<int> key, Span<byte> rvec,
int length)
174 var xmm_key_shuf_mask = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(AESCrypt_x86.KeyShuffleMask)).AsByte();
176 const int XMM_REG_NUM_KEY_FIRST = 2;
177 const int XMM_REG_NUM_KEY_LAST = 7;
179 Span<Vector128<byte>> xmm_key = stackalloc Vector128<byte>[6];
180 ref Vector128<byte> xmm_key0 =
ref MemoryMarshal.GetReference(xmm_key);
181 for (
int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x00; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
183 xmm_key[as_XMMRegister(rnum)] = AESCrypt_x86.LoadKey(key, (nuint)offset, xmm_key_shuf_mask);
187 var xmm_result = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(rvec));
189 if (key.Length != 44)
196 var xmm_temp = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(from), pos);
197 xmm_result = Sse2.Xor(xmm_result, xmm_temp);
198 xmm_result = Sse2.Xor(xmm_result, xmm_key0);
199 for (
int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
201 xmm_result = Aes.Encrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]);
204 for (
int key_offset = 0x60; key_offset <= 0x90; key_offset += 0x10)
206 xmm_result = AesEncKey(xmm_result, key, (nuint)key_offset);
209 xmm_temp = AESCrypt_x86.LoadKey(key, 0xa0);
210 xmm_result = Aes.EncryptLast(xmm_result, xmm_temp);
211 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(to), pos);
213 length -= AESBlockSize;
220 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(rvec));
224 if (key.Length != 52)
231 xmm_temp = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(from), pos);
232 xmm_result = Sse2.Xor(xmm_result, xmm_temp);
233 xmm_result = Sse2.Xor(xmm_result, xmm_key0);
234 for (
int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
236 xmm_result = Aes.Encrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]);
239 for (nuint key_offset = 0x60; key_offset <= 0xb0; key_offset += 0x10)
241 xmm_result = AesEncKey(xmm_result, key, key_offset);
244 xmm_temp = AESCrypt_x86.LoadKey(key, 0xc0);
245 xmm_result = Aes.EncryptLast(xmm_result, xmm_temp);
246 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(to), pos);
248 length -= AESBlockSize;
259 xmm_temp = Vector128Util.LoadUnsafe(in MemoryMarshal.GetReference(from), pos);
260 xmm_result = Sse2.Xor(xmm_result, xmm_temp);
261 xmm_result = Sse2.Xor(xmm_result, xmm_key0);
262 for (
int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++)
264 xmm_result = Aes.Encrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]);
267 for (nuint key_offset = 0x60; key_offset <= 0xd0; key_offset += 0x10)
269 xmm_result = AesEncKey(xmm_result, key, key_offset);
272 xmm_temp = AESCrypt_x86.LoadKey(key, 0xe0);
273 xmm_result = Aes.EncryptLast(xmm_result, xmm_temp);
274 xmm_result.StoreUnsafe(
ref MemoryMarshal.GetReference(to), pos);
276 length -= AESBlockSize;
285 static Vector128<byte> AesDecKey(Vector128<byte> xmmdst, ReadOnlySpan<int> key, nuint offset, Vector128<byte>? xmm_shuf_mask =
null)
287 return Aes.Decrypt(xmmdst, AESCrypt_x86.LoadKey(key, offset, xmm_shuf_mask));
290 static Vector128<byte> AesEncKey(Vector128<byte> xmmdst, ReadOnlySpan<int> key, nuint offset, Vector128<byte>? xmm_shuf_mask =
null)
292 return Aes.Encrypt(xmmdst, AESCrypt_x86.LoadKey(key, offset, xmm_shuf_mask));
295 static int as_XMMRegister(
int @in) => @in - 2;