From bb27e98655453ca7d28da70fe5aa5cb860f1cbf7 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Mon, 6 Jan 2025 15:58:06 +0100 Subject: [PATCH 01/13] AESCrypt encryptBlock X86 --- src/IKVM.Java/map.xml | 16 ++++ .../com/sun/crypto/provider/AESCrypt.X86.cs | 77 +++++++++++++++++++ .../com/sun/crypto/provider/AESCrypt.cs | 25 ++++++ 3 files changed, 118 insertions(+) create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs diff --git a/src/IKVM.Java/map.xml b/src/IKVM.Java/map.xml index f4ea2a3c4..6e29f5440 100644 --- a/src/IKVM.Java/map.xml +++ b/src/IKVM.Java/map.xml @@ -1638,6 +1638,22 @@ + + + + + + + + + + + + + + + diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs new file mode 100644 index 000000000..4873c9cfc --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -0,0 +1,77 @@ +#if NETCOREAPP3_0_OR_GREATER +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace IKVM.Runtime.Java.Externs.com.sun.crypto.provider; + +partial class AESCrypt +{ + private static bool IsSupportedX86 => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; + + private static Vector128 LoadKey_X86(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) + { + Vector128 xmmdest = Vector128.Create(key, offset).AsBytes(); + shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); + Ssse3.Shuffle(xmmdest, shuffle_mask.Value); + return xmmdest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void EncryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + { + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; + Vector128 xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + Vector128 xmm_result = Vector128.Create(@in, inOffset); + + xmm_temp1 = LoadKey_X86(K, 0, xmm_key_shuf_mask); + Sse2.Xor(xmm_result, xmm_temp1); + + xmm_temp1 = LoadKey_X86(K, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey_X86(K, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey_X86(K, 0x40, xmm_key_shuf_mask); + + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey_X86(K, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey_X86(K, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey_X86(K, 0x80, xmm_key_shuf_mask); + + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey_X86(K, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0xa0, xmm_key_shuf_mask); + + if (K.Length != 11) + { + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey_X86(K, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0xc0, xmm_key_shuf_mask); + + if (K.Length != 13) + { + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey_X86(K, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0xe0, xmm_key_shuf_mask); + } + } + + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); + _ = xmm_result.TryCopyTo(@out.AsSpan(outOffset)); + } +} +#endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs new file mode 100644 index 000000000..8a4550e93 --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -0,0 +1,25 @@ +#if NETCOREAPP3_0_OR_GREATER +using System; +#endif + +namespace IKVM.Runtime.Java.Externs.com.sun.crypto.provider; + +internal static partial class AESCrypt +{ + public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + { +#if NETCOREAPP3_0_OR_GREATER + if (IsSupportedX86) + { + EncryptBlock_X86(@in, inOffset, @out, outOffset, K); + return true; + } +#endif + + return false; + } + +#if NETCOREAPP3_0_OR_GREATER + private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; +#endif +} From 3bcad11e858863e64b964ad256b39223de0d1f7c Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 11:15:43 +0100 Subject: [PATCH 02/13] Fix namespace --- .../Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs | 2 +- .../Java/Externs/com/sun/crypto/provider/AESCrypt.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 4873c9cfc..dd54beaab 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -4,7 +4,7 @@ using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -namespace IKVM.Runtime.Java.Externs.com.sun.crypto.provider; +namespace IKVM.Java.Externs.com.sun.crypto.provider; partial class AESCrypt { diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index 8a4550e93..128285311 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -2,7 +2,7 @@ using System; #endif -namespace IKVM.Runtime.Java.Externs.com.sun.crypto.provider; +namespace IKVM.Java.Externs.com.sun.crypto.provider; internal static partial class AESCrypt { From 33ba1bcc06cce8bb20f5eeea8f0d545062491653 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 11:18:17 +0100 Subject: [PATCH 03/13] Fix Vector128 creation on .NET 6 --- .../com/sun/crypto/provider/AESCrypt.X86.cs | 23 ++++++++-- .../com/sun/crypto/provider/AESCrypt.cs | 2 - .../sun/crypto/provider/Vector128Polyfill.cs | 45 +++++++++++++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index dd54beaab..2c7f08d55 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -12,8 +12,13 @@ partial class AESCrypt private static Vector128 LoadKey_X86(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) { - Vector128 xmmdest = Vector128.Create(key, offset).AsBytes(); +#if NET8_0_OR_GREATER + var xmmdest = Vector128.Create(key[offset..]).AsByte(); shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); +#else + var xmmdest = Vector128Polyfill.Create(key).AsByte(); + shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); +#endif Ssse3.Shuffle(xmmdest, shuffle_mask.Value); return xmmdest; } @@ -21,11 +26,18 @@ private static Vector128 LoadKey_X86(ReadOnlySpan key, int offset, Ve [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void EncryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; - Vector128 xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - Vector128 xmm_result = Vector128.Create(@in, inOffset); +#if NET8_0_OR_GREATER + var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128.Create(@in, inOffset); +#else + var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128Polyfill.Create(@in, inOffset); +#endif - xmm_temp1 = LoadKey_X86(K, 0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey_X86(K, 0x00, xmm_key_shuf_mask); Sse2.Xor(xmm_result, xmm_temp1); xmm_temp1 = LoadKey_X86(K, 0x10, xmm_key_shuf_mask); @@ -51,6 +63,9 @@ private static void EncryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int xmm_temp1 = LoadKey_X86(K, 0x90, xmm_key_shuf_mask); xmm_temp2 = LoadKey_X86(K, 0xa0, xmm_key_shuf_mask); + /* + * ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 + */ if (K.Length != 11) { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index 128285311..7ce230aaa 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -1,6 +1,4 @@ -#if NETCOREAPP3_0_OR_GREATER using System; -#endif namespace IKVM.Java.Externs.com.sun.crypto.provider; diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs new file mode 100644 index 000000000..bc3af0093 --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs @@ -0,0 +1,45 @@ +#if NETCOREAPP3_0_OR_GREATER && !(NET8_0_OR_GREATER) +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace IKVM.Java.Externs.com.sun.crypto.provider; + +internal static class Vector128Polyfill +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Create(ReadOnlySpan values) where T : unmanaged + { + if (values.Length < Vector128.Count) + { + throw new ArgumentOutOfRangeException(nameof(values)); + } + + return Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Create(T[] values, int index) where T : unmanaged + { + if ((index < 0) || ((values.Length - index) < Vector128.Count)) + { + throw new IndexOutOfRangeException(nameof(values)); + } + + return Unsafe.ReadUnaligned>(ref Unsafe.As(ref values[index])); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryCopyTo(this Vector128 vector, Span destination) where T : unmanaged + { + if (destination.Length < Vector128.Count) + { + return false; + } + + Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); + return true; + } +} +#endif From b9c9e9e0a34cb13f540101876b1321cacb561d81 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 11:19:52 +0100 Subject: [PATCH 04/13] Aes Decrypt --- src/IKVM.Java/map.xml | 14 +++++ .../com/sun/crypto/provider/AESCrypt.X86.cs | 62 +++++++++++++++++++ .../com/sun/crypto/provider/AESCrypt.cs | 13 ++++ 3 files changed, 89 insertions(+) diff --git a/src/IKVM.Java/map.xml b/src/IKVM.Java/map.xml index 6e29f5440..575533fec 100644 --- a/src/IKVM.Java/map.xml +++ b/src/IKVM.Java/map.xml @@ -1653,6 +1653,20 @@ + + + + + + + + + + + + + diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 2c7f08d55..91a60fe03 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -88,5 +88,67 @@ private static void EncryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); _ = xmm_result.TryCopyTo(@out.AsSpan(outOffset)); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void DecryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 + + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; +#if NET8_0_OR_GREATER + var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128.Create(@in, inOffset); +#else + var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128Polyfill.Create(@in, inOffset); +#endif + + xmm_temp1 = LoadKey_X86(K, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey_X86(K, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey_X86(K, 0x40, xmm_key_shuf_mask); + + xmm_result = Sse2.Xor(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey_X86(K, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey_X86(K, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey_X86(K, 0x80, xmm_key_shuf_mask); + + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey_X86(K, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0xa0, xmm_key_shuf_mask); + xmm_temp3 = LoadKey_X86(K, 0x00, xmm_key_shuf_mask); + + if (K.Length != 11) + { + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey_X86(K, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0xc0, xmm_key_shuf_mask); + + if (K.Length != 13) + { + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey_X86(K, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey_X86(K, 0xe0, xmm_key_shuf_mask); + } + } + + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); + _ = xmm_result.TryCopyTo(@out.AsSpan(outOffset)); + } } #endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index 7ce230aaa..aba1a77dd 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -17,6 +17,19 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf return false; } + public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + { +#if NETCOREAPP3_0_OR_GREATER + if (IsSupportedX86) + { + DecryptBlock_X86(@in, inOffset, @out, outOffset, K); + return true; + } +#endif + + return false; + } + #if NETCOREAPP3_0_OR_GREATER private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; #endif From 41eb38fedbe734718a8e03714b81603bd034ff70 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 11:51:30 +0100 Subject: [PATCH 05/13] Move ref structs to nested classes Make this as less error-prone as possible for IKVM consumers --- .../com/sun/crypto/provider/AESCrypt.X86.cs | 200 +++++++++--------- .../com/sun/crypto/provider/AESCrypt.cs | 15 +- .../sun/crypto/provider/Vector128Polyfill.cs | 70 +++--- 3 files changed, 148 insertions(+), 137 deletions(-) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 91a60fe03..32a22c9f1 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -8,147 +8,149 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider; partial class AESCrypt { - private static bool IsSupportedX86 => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; - - private static Vector128 LoadKey_X86(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) + partial class X86 { + public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; + + private static Vector128 LoadKey(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) + { #if NET8_0_OR_GREATER - var xmmdest = Vector128.Create(key[offset..]).AsByte(); - shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); + var xmmdest = Vector128.Create(key[offset..]).AsByte(); + shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); #else - var xmmdest = Vector128Polyfill.Create(key).AsByte(); - shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmmdest = Vector128Polyfill.Create(key[offset..]).AsByte(); + shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); #endif - Ssse3.Shuffle(xmmdest, shuffle_mask.Value); - return xmmdest; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void EncryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) - { - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 + Ssse3.Shuffle(xmmdest, shuffle_mask.Value); + return xmmdest; + } - Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in, inOffset); + var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128.Create(@in, inOffset); #else - var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in, inOffset); + var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128Polyfill.Create(@in, inOffset); #endif - xmm_temp1 = LoadKey_X86(K, 0x00, xmm_key_shuf_mask); - Sse2.Xor(xmm_result, xmm_temp1); + xmm_temp1 = LoadKey(K, 0x00, xmm_key_shuf_mask); + Sse2.Xor(xmm_result, xmm_temp1); - xmm_temp1 = LoadKey_X86(K, 0x10, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0x20, xmm_key_shuf_mask); - xmm_temp3 = LoadKey_X86(K, 0x30, xmm_key_shuf_mask); - xmm_temp4 = LoadKey_X86(K, 0x40, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); - - xmm_temp1 = LoadKey_X86(K, 0x50, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0x60, xmm_key_shuf_mask); - xmm_temp3 = LoadKey_X86(K, 0x70, xmm_key_shuf_mask); - xmm_temp4 = LoadKey_X86(K, 0x80, xmm_key_shuf_mask); - - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey_X86(K, 0x90, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0xa0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); - /* - * ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 - */ - if (K.Length != 11) - { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey_X86(K, 0xb0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0xc0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); - if (K.Length != 13) + /* + * ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 + */ + if (K.Length != 11) { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - xmm_temp1 = LoadKey_X86(K, 0xd0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0xe0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); + + if (K.Length != 13) + { + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); + } } - } - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); - _ = xmm_result.TryCopyTo(@out.AsSpan(outOffset)); - } + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); + xmm_result.CopyTo(@out, outOffset); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void DecryptBlock_X86(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) - { - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 - Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in, inOffset); + var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128.Create(@in, inOffset); #else - var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in, inOffset); + var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128Polyfill.Create(@in, inOffset); #endif - xmm_temp1 = LoadKey_X86(K, 0x10, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0x20, xmm_key_shuf_mask); - xmm_temp3 = LoadKey_X86(K, 0x30, xmm_key_shuf_mask); - xmm_temp4 = LoadKey_X86(K, 0x40, xmm_key_shuf_mask); - - xmm_result = Sse2.Xor(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); - xmm_temp1 = LoadKey_X86(K, 0x50, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0x60, xmm_key_shuf_mask); - xmm_temp3 = LoadKey_X86(K, 0x70, xmm_key_shuf_mask); - xmm_temp4 = LoadKey_X86(K, 0x80, xmm_key_shuf_mask); - - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + xmm_result = Sse2.Xor(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey_X86(K, 0x90, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0xa0, xmm_key_shuf_mask); - xmm_temp3 = LoadKey_X86(K, 0x00, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); - if (K.Length != 11) - { xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey_X86(K, 0xb0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0xc0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x00, xmm_key_shuf_mask); - if (K.Length != 13) + if (K.Length != 11) { xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_temp1 = LoadKey_X86(K, 0xd0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey_X86(K, 0xe0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); + + if (K.Length != 13) + { + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); + } } - } - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); - _ = xmm_result.TryCopyTo(@out.AsSpan(outOffset)); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); + xmm_result.CopyTo(@out, outOffset); + } } } #endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index aba1a77dd..ec96f6472 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -1,15 +1,17 @@ +using IKVM.Attributes; using System; namespace IKVM.Java.Externs.com.sun.crypto.provider; +[HideFromJava] internal static partial class AESCrypt { public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER - if (IsSupportedX86) + if (X86.IsSupported) { - EncryptBlock_X86(@in, inOffset, @out, outOffset, K); + X86.EncryptBlock(@in, inOffset, @out, outOffset, K); return true; } #endif @@ -20,9 +22,9 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER - if (IsSupportedX86) + if (X86.IsSupported) { - DecryptBlock_X86(@in, inOffset, @out, outOffset, K); + X86.DecryptBlock(@in, inOffset, @out, outOffset, K); return true; } #endif @@ -31,6 +33,9 @@ public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf } #if NETCOREAPP3_0_OR_GREATER - private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; + private static partial class X86 + { + public static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; + } #endif } diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs index bc3af0093..28f116add 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs @@ -8,38 +8,42 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider; internal static class Vector128Polyfill { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Create(ReadOnlySpan values) where T : unmanaged - { - if (values.Length < Vector128.Count) - { - throw new ArgumentOutOfRangeException(nameof(values)); - } - - return Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Create(T[] values, int index) where T : unmanaged - { - if ((index < 0) || ((values.Length - index) < Vector128.Count)) - { - throw new IndexOutOfRangeException(nameof(values)); - } - - return Unsafe.ReadUnaligned>(ref Unsafe.As(ref values[index])); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool TryCopyTo(this Vector128 vector, Span destination) where T : unmanaged - { - if (destination.Length < Vector128.Count) - { - return false; - } - - Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); - return true; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Create(ReadOnlySpan values) where T : unmanaged + { + if (values.Length < Vector128.Count) + { + throw new ArgumentOutOfRangeException(nameof(values)); + } + + return Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Create(T[] values, int index) where T : unmanaged + { + if ((index < 0) || ((values.Length - index) < Vector128.Count)) + { + throw new IndexOutOfRangeException(nameof(values)); + } + + return Unsafe.ReadUnaligned>(ref Unsafe.As(ref values[index])); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyTo(this Vector128 vector, T[] destination, int startIndex) where T : unmanaged + { + if ((uint)startIndex >= (uint)destination.Length) + { + throw new IndexOutOfRangeException(nameof(startIndex)); + } + + if ((destination.Length - startIndex) < Vector128.Count) + { + throw new ArgumentException(null, nameof(destination)); + } + + Unsafe.WriteUnaligned(ref Unsafe.As(ref destination[startIndex]), vector); + } } #endif From 18ed0126547f1348bbdc5d18e1e12246108eab0f Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 11:55:52 +0100 Subject: [PATCH 06/13] Inline --- .../Java/Externs/com/sun/crypto/provider/AESCrypt.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index ec96f6472..224091353 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -1,11 +1,13 @@ using IKVM.Attributes; using System; +using System.Runtime.CompilerServices; namespace IKVM.Java.Externs.com.sun.crypto.provider; [HideFromJava] internal static partial class AESCrypt { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER @@ -19,6 +21,7 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf return false; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER From 2a9a5796cd94109f647beddc12caf1374928c120 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 12:59:48 +0100 Subject: [PATCH 07/13] Fix map --- src/IKVM.Java/map.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/IKVM.Java/map.xml b/src/IKVM.Java/map.xml index 575533fec..26e451cb1 100644 --- a/src/IKVM.Java/map.xml +++ b/src/IKVM.Java/map.xml @@ -1641,10 +1641,11 @@ - + + @@ -1655,10 +1656,11 @@ - + + From 63bdfaf3d37841af0864f8bb85cdccf70553efa0 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 14:03:17 +0100 Subject: [PATCH 08/13] Reuse as much of the Hotspot offsets Requires mem-casting the Int32-key to Int8 --- .../com/sun/crypto/provider/AESCrypt.X86.cs | 23 +++++++++---------- .../com/sun/crypto/provider/AESCrypt.cs | 7 +++--- .../sun/crypto/provider/Vector128Polyfill.cs | 22 +++--------------- 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 32a22c9f1..93128fa62 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -12,13 +12,13 @@ partial class X86 { public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; - private static Vector128 LoadKey(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) + private static Vector128 LoadKey(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) { #if NET8_0_OR_GREATER - var xmmdest = Vector128.Create(key[offset..]).AsByte(); + var xmmdest = Vector128.Create(key[offset..]); shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); #else - var xmmdest = Vector128Polyfill.Create(key[offset..]).AsByte(); + var xmmdest = Vector128Polyfill.Create(key[offset..]); shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); #endif Ssse3.Shuffle(xmmdest, shuffle_mask.Value); @@ -26,16 +26,16 @@ private static Vector128 LoadKey(ReadOnlySpan key, int offset, Vector } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) { // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in, inOffset); + var xmm_result = Vector128.Create(@in); #else var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in, inOffset); + var xmm_result = Vector128Polyfill.Create(@in); #endif xmm_temp1 = LoadKey(K, 0x00, xmm_key_shuf_mask); @@ -87,21 +87,20 @@ public static void EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); - xmm_result.CopyTo(@out, outOffset); + xmm_result.CopyTo(@out); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) { // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 - Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in, inOffset); + var xmm_result = Vector128.Create(@in); #else var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in, inOffset); + var xmm_result = Vector128Polyfill.Create(@in); #endif xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); @@ -149,7 +148,7 @@ public static void DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); - xmm_result.CopyTo(@out, outOffset); + xmm_result.CopyTo(@out); } } } diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index 224091353..4bba9f162 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -1,6 +1,7 @@ using IKVM.Attributes; using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace IKVM.Java.Externs.com.sun.crypto.provider; @@ -13,7 +14,7 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf #if NETCOREAPP3_0_OR_GREATER if (X86.IsSupported) { - X86.EncryptBlock(@in, inOffset, @out, outOffset, K); + X86.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), MemoryMarshal.AsBytes((ReadOnlySpan)K)); return true; } #endif @@ -27,7 +28,7 @@ public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf #if NETCOREAPP3_0_OR_GREATER if (X86.IsSupported) { - X86.DecryptBlock(@in, inOffset, @out, outOffset, K); + X86.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), MemoryMarshal.AsBytes((ReadOnlySpan)K)); return true; } #endif @@ -38,7 +39,7 @@ public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf #if NETCOREAPP3_0_OR_GREATER private static partial class X86 { - public static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; + private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; } #endif } diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs index 28f116add..1957cfd42 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs @@ -20,30 +20,14 @@ public static Vector128 Create(ReadOnlySpan values) where T : unmanaged } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Create(T[] values, int index) where T : unmanaged + public static void CopyTo(this Vector128 vector, Span destination) where T : unmanaged { - if ((index < 0) || ((values.Length - index) < Vector128.Count)) - { - throw new IndexOutOfRangeException(nameof(values)); - } - - return Unsafe.ReadUnaligned>(ref Unsafe.As(ref values[index])); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void CopyTo(this Vector128 vector, T[] destination, int startIndex) where T : unmanaged - { - if ((uint)startIndex >= (uint)destination.Length) - { - throw new IndexOutOfRangeException(nameof(startIndex)); - } - - if ((destination.Length - startIndex) < Vector128.Count) + if (destination.Length < Vector128.Count) { throw new ArgumentException(null, nameof(destination)); } - Unsafe.WriteUnaligned(ref Unsafe.As(ref destination[startIndex]), vector); + Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); } } #endif From 3da311373af32409175b2c8b895a3463b22c8418 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Tue, 7 Jan 2025 18:43:09 +0100 Subject: [PATCH 09/13] Fixes --- .../com/sun/crypto/provider/AESCrypt.X86.cs | 29 +++++++++---------- .../com/sun/crypto/provider/AESCrypt.cs | 4 +-- .../sun/crypto/provider/Vector128Polyfill.cs | 13 +++++++-- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 93128fa62..68697269f 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -1,6 +1,7 @@ #if NETCOREAPP3_0_OR_GREATER using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; @@ -12,21 +13,21 @@ partial class X86 { public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; - private static Vector128 LoadKey(ReadOnlySpan key, int offset, Vector128? shuffle_mask = null) + private static Vector128 LoadKey(ReadOnlySpan key, nuint offset, Vector128? shuffle_mask = null) { #if NET8_0_OR_GREATER - var xmmdest = Vector128.Create(key[offset..]); + var xmmdest = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); #else - var xmmdest = Vector128Polyfill.Create(key[offset..]); + var xmmdest = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); #endif - Ssse3.Shuffle(xmmdest, shuffle_mask.Value); - return xmmdest; + + return Ssse3.Shuffle(xmmdest, shuffle_mask.Value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) + public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) { // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; @@ -39,7 +40,7 @@ public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnl #endif xmm_temp1 = LoadKey(K, 0x00, xmm_key_shuf_mask); - Sse2.Xor(xmm_result, xmm_temp1); + xmm_result = Sse2.Xor(xmm_result, xmm_temp1); xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); @@ -64,10 +65,8 @@ public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnl xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); - /* - * ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 - */ - if (K.Length != 11) + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 + if (K.Length != 44) { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); @@ -75,7 +74,7 @@ public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnl xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - if (K.Length != 13) + if (K.Length != 52) { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); @@ -91,7 +90,7 @@ public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnl } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) + public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) { // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; @@ -127,7 +126,7 @@ public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnl xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); xmm_temp3 = LoadKey(K, 0x00, xmm_key_shuf_mask); - if (K.Length != 11) + if (K.Length != 44) { xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); @@ -135,7 +134,7 @@ public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnl xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - if (K.Length != 13) + if (K.Length != 52) { xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index 4bba9f162..f03f0ff4c 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -14,7 +14,7 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf #if NETCOREAPP3_0_OR_GREATER if (X86.IsSupported) { - X86.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), MemoryMarshal.AsBytes((ReadOnlySpan)K)); + X86.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); return true; } #endif @@ -28,7 +28,7 @@ public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf #if NETCOREAPP3_0_OR_GREATER if (X86.IsSupported) { - X86.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), MemoryMarshal.AsBytes((ReadOnlySpan)K)); + X86.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); return true; } #endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs index 1957cfd42..7f9fe18e7 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs @@ -9,7 +9,16 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider; internal static class Vector128Polyfill { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Create(ReadOnlySpan values) where T : unmanaged + public static Vector128 LoadUnsafe(ref readonly T source, nuint elementOffset) where T : struct + { + // Use with caution. + // Supports blittable primitives only. + ref byte address = ref Unsafe.As(ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset)); + return Unsafe.ReadUnaligned>(ref address); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Create(ReadOnlySpan values) where T : struct { if (values.Length < Vector128.Count) { @@ -20,7 +29,7 @@ public static Vector128 Create(ReadOnlySpan values) where T : unmanaged } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void CopyTo(this Vector128 vector, Span destination) where T : unmanaged + public static void CopyTo(this Vector128 vector, Span destination) where T : struct { if (destination.Length < Vector128.Count) { From c11f0eac790c058875ca332768c1ee26bde45d95 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Thu, 9 Jan 2025 16:42:38 +0100 Subject: [PATCH 10/13] Move AESCrypt to namespace (keep suffixed filename) --- .../com/sun/crypto/provider/AESCrypt.X86.cs | 195 +++++++++--------- .../com/sun/crypto/provider/AESCrypt.cs | 18 +- 2 files changed, 102 insertions(+), 111 deletions(-) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 68697269f..485b10751 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -5,150 +5,149 @@ using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -namespace IKVM.Java.Externs.com.sun.crypto.provider; +namespace IKVM.Java.Externs.com.sun.crypto.provider.X86; -partial class AESCrypt +internal static class AESCrypt { - partial class X86 - { - public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; + public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; - private static Vector128 LoadKey(ReadOnlySpan key, nuint offset, Vector128? shuffle_mask = null) - { + private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; + + private static Vector128 LoadKey(ReadOnlySpan key, nuint offset, Vector128? shuffle_mask = null) + { #if NET8_0_OR_GREATER - var xmmdest = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); - shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); + var xmmdest = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); + shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); #else - var xmmdest = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); - shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmmdest = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); + shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); #endif - return Ssse3.Shuffle(xmmdest, shuffle_mask.Value); - } + return Ssse3.Shuffle(xmmdest, shuffle_mask.Value); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) - { - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 - Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in); + var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128.Create(@in); #else - var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in); + var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128Polyfill.Create(@in); #endif - xmm_temp1 = LoadKey(K, 0x00, xmm_key_shuf_mask); - xmm_result = Sse2.Xor(xmm_result, xmm_temp1); + xmm_temp1 = LoadKey(K, 0x00, xmm_key_shuf_mask); + xmm_result = Sse2.Xor(xmm_result, xmm_temp1); - xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); - xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); + xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); + + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 + if (K.Length != 44) + { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 - if (K.Length != 44) + if (K.Length != 52) { xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - - if (K.Length != 52) - { - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - - xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); - } + xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); } - - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); - xmm_result.CopyTo(@out); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) - { - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 - Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); + xmm_result.CopyTo(@out); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in); + var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_result = Vector128.Create(@in); #else var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); var xmm_result = Vector128Polyfill.Create(@in); #endif - xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); - xmm_result = Sse2.Xor(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + xmm_result = Sse2.Xor(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); - xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(K, 0x00, xmm_key_shuf_mask); + + if (K.Length != 44) + { xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x00, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - if (K.Length != 44) + if (K.Length != 52) { xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - - if (K.Length != 52) - { - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - - xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); - } + xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); } - - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); - xmm_result.CopyTo(@out); } + + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); + xmm_result.CopyTo(@out); } } #endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index f03f0ff4c..aff7643af 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -1,20 +1,19 @@ using IKVM.Attributes; using System; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace IKVM.Java.Externs.com.sun.crypto.provider; [HideFromJava] -internal static partial class AESCrypt +internal static class AESCrypt { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER - if (X86.IsSupported) + if (X86.AESCrypt.IsSupported) { - X86.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); + X86.AESCrypt.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); return true; } #endif @@ -26,20 +25,13 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER - if (X86.IsSupported) + if (X86.AESCrypt.IsSupported) { - X86.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); + X86.AESCrypt.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); return true; } #endif return false; } - -#if NETCOREAPP3_0_OR_GREATER - private static partial class X86 - { - private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; - } -#endif } From f209701f4a4852ff933c17bfa210d46feb8fd20a Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Thu, 9 Jan 2025 17:50:24 +0100 Subject: [PATCH 11/13] Implement GHASH on X86 --- src/IKVM.Java/map.xml | 16 +++ .../com/sun/crypto/provider/GHASH.X86.cs | 129 ++++++++++++++++++ .../Externs/com/sun/crypto/provider/GHASH.cs | 21 +++ .../sun/crypto/provider/Vector128Polyfill.cs | 9 ++ 4 files changed, 175 insertions(+) create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.cs diff --git a/src/IKVM.Java/map.xml b/src/IKVM.Java/map.xml index 26e451cb1..f3fe1cc77 100644 --- a/src/IKVM.Java/map.xml +++ b/src/IKVM.Java/map.xml @@ -1670,6 +1670,22 @@ + + + + + + + + + + + + + + + diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs new file mode 100644 index 000000000..516781d16 --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs @@ -0,0 +1,129 @@ +#if NETCOREAPP3_0_OR_GREATER +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace IKVM.Java.Externs.com.sun.crypto.provider.X86; + +internal static class GHASH +{ + public static bool IsSupported => Pclmulqdq.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; + + private static ReadOnlySpan ByteSwapMask => [0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203]; + + private static ReadOnlySpan LongSwapMask => [0x0b0a0908, 0x0f0e0d0c, 0x03020100, 0x07060504]; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ProcessBlocks(ReadOnlySpan data, int blocks, Span state, ReadOnlySpan subH) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2748-2883 + Vector128 + xmm_temp0, + xmm_temp1, + xmm_temp2, + xmm_temp3, + xmm_temp4, + xmm_temp5, + xmm_temp6, + xmm_temp7; + +#if NET8_0_OR_GREATER + xmm_temp0 = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(state)), 0); + xmm_temp0 = Ssse3.Shuffle(xmm_temp0.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); + xmm_temp1 = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(subH)), 0); + xmm_temp1 = Ssse3.Shuffle(xmm_temp1.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); +#else + xmm_temp0 = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(state)), 0); + xmm_temp0 = Ssse3.Shuffle(xmm_temp0.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); + xmm_temp1 = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(subH)), 0); + xmm_temp1 = Ssse3.Shuffle(xmm_temp1.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); +#endif + + ghash_loop: +#if NET8_0_OR_GREATER + xmm_temp2 = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(data)), 0); + xmm_temp2 = Ssse3.Shuffle(xmm_temp2.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(ByteSwapMask)))).AsInt32(); +#else + xmm_temp2 = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(data)), 0); + xmm_temp2 = Ssse3.Shuffle(xmm_temp2.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(ByteSwapMask)))).AsInt32(); +#endif + xmm_temp0 = Sse2.Xor(xmm_temp0, xmm_temp2); + + xmm_temp3 = xmm_temp0; + xmm_temp3 = Pclmulqdq.CarrylessMultiply(xmm_temp3.AsInt64(), xmm_temp1.AsInt64(), 0).AsInt32(); + xmm_temp4 = xmm_temp0; + xmm_temp4 = Pclmulqdq.CarrylessMultiply(xmm_temp4.AsInt64(), xmm_temp1.AsInt64(), 16).AsInt32(); + + xmm_temp5 = xmm_temp0; + xmm_temp5 = Pclmulqdq.CarrylessMultiply(xmm_temp5.AsInt64(), xmm_temp1.AsInt64(), 1).AsInt32(); + xmm_temp6 = xmm_temp0; + xmm_temp6 = Pclmulqdq.CarrylessMultiply(xmm_temp6.AsInt64(), xmm_temp1.AsInt64(), 17).AsInt32(); + + xmm_temp4 = Sse2.Xor(xmm_temp4, xmm_temp5); + + xmm_temp5 = xmm_temp4; + xmm_temp4 = Sse2.ShiftRightLogical128BitLane(xmm_temp4, 8); + xmm_temp5 = Sse2.ShiftLeftLogical128BitLane(xmm_temp5, 8); + xmm_temp3 = Sse2.Xor(xmm_temp3, xmm_temp5); + xmm_temp6 = Sse2.Xor(xmm_temp6, xmm_temp4); + + xmm_temp7 = xmm_temp3; + xmm_temp4 = xmm_temp6; + xmm_temp3 = Sse2.ShiftLeftLogical(xmm_temp3, 1); + xmm_temp6 = Sse2.ShiftLeftLogical(xmm_temp6, 1); + xmm_temp7 = Sse2.ShiftRightLogical(xmm_temp7, 31); + xmm_temp4 = Sse2.ShiftRightLogical(xmm_temp4, 31); + xmm_temp5 = xmm_temp7; + xmm_temp4 = Sse2.ShiftLeftLogical128BitLane(xmm_temp4, 4); + xmm_temp7 = Sse2.ShiftLeftLogical128BitLane(xmm_temp7, 4); + xmm_temp5 = Sse2.ShiftRightLogical128BitLane(xmm_temp5, 12); + xmm_temp3 = Sse2.Or(xmm_temp3, xmm_temp7); + xmm_temp6 = Sse2.Or(xmm_temp6, xmm_temp4); + xmm_temp6 = Sse2.Or(xmm_temp6, xmm_temp5); + + xmm_temp7 = xmm_temp3; + xmm_temp4 = xmm_temp3; + xmm_temp5 = xmm_temp3; + xmm_temp7 = Sse2.ShiftLeftLogical(xmm_temp7, 31); + xmm_temp4 = Sse2.ShiftLeftLogical(xmm_temp4, 30); + xmm_temp5 = Sse2.ShiftLeftLogical(xmm_temp5, 25); + xmm_temp7 = Sse2.Xor(xmm_temp7, xmm_temp4); + xmm_temp7 = Sse2.Xor(xmm_temp7, xmm_temp5); + xmm_temp4 = xmm_temp7; + xmm_temp7 = Sse2.ShiftLeftLogical128BitLane(xmm_temp7, 12); + xmm_temp4 = Sse2.ShiftRightLogical128BitLane(xmm_temp4, 4); + xmm_temp3 = Sse2.Xor(xmm_temp3, xmm_temp7); + + xmm_temp2 = xmm_temp3; + xmm_temp7 = xmm_temp3; + xmm_temp5 = xmm_temp3; + xmm_temp2 = Sse2.ShiftRightLogical(xmm_temp2, 1); + xmm_temp7 = Sse2.ShiftRightLogical(xmm_temp7, 2); + xmm_temp5 = Sse2.ShiftRightLogical(xmm_temp5, 7); + xmm_temp2 = Sse2.Xor(xmm_temp2, xmm_temp7); + xmm_temp2 = Sse2.Xor(xmm_temp2, xmm_temp5); + xmm_temp2 = Sse2.Xor(xmm_temp2, xmm_temp4); + xmm_temp3 = Sse2.Xor(xmm_temp3, xmm_temp2); + xmm_temp6 = Sse2.Xor(xmm_temp6, xmm_temp3); + if ((--blocks) == 0) + { + goto exit; + } + + xmm_temp0 = xmm_temp6; + data = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref Unsafe.AsRef(in MemoryMarshal.GetReference(data)), 16), data.Length - 16); + goto ghash_loop; + + exit:; +#if NET8_0_OR_GREATER + Ssse3.Shuffle(xmm_temp6.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))) + .AsInt64().CopyTo(state); +#else + Ssse3.Shuffle(xmm_temp6.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))) + .AsInt64().CopyTo(state); +#endif + } +} +#endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.cs new file mode 100644 index 000000000..90035b476 --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.cs @@ -0,0 +1,21 @@ +using System; +using System.Runtime.CompilerServices; + +namespace IKVM.Java.Externs.com.sun.crypto.provider; + +internal static class GHASH +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ProcessBlocks(byte[] data, int inOfs, int blocks, long[] st, long[] subH) + { +#if NETCOREAPP3_0_OR_GREATER + if (X86.GHASH.IsSupported) + { + X86.GHASH.ProcessBlocks(data.AsSpan(inOfs), blocks, st, subH); + return true; + } +#endif + + return false; + } +} diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs index 7f9fe18e7..92b4b07af 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs @@ -8,6 +8,15 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider; internal static class Vector128Polyfill { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 LoadUnsafe(ref readonly T source) where T : struct + { + // Use with caution. + // Supports blittable primitives only. + ref byte address = ref Unsafe.As(ref Unsafe.AsRef(in source)); + return Unsafe.ReadUnaligned>(ref address); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 LoadUnsafe(ref readonly T source, nuint elementOffset) where T : struct { From 06817f090da6105c31c60d14210006dee2058df3 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Fri, 10 Jan 2025 12:11:22 +0100 Subject: [PATCH 12/13] Add CipherBlockChaining X86 --- src/IKVM.Java/map.xml | 46 ++- .../Sun/Crypto/Provider/AESCryptAccessor.cs | 13 + .../com/sun/crypto/provider/AESCrypt.X86.cs | 194 +++++------ .../com/sun/crypto/provider/AESCrypt.cs | 8 +- .../provider/CipherBlockChaining.X86.cs | 312 ++++++++++++++++++ .../crypto/provider/CipherBlockChaining.cs | 63 ++++ .../com/sun/crypto/provider/GHASH.X86.cs | 30 +- .../sun/crypto/provider/Vector128Polyfill.cs | 48 ++- 8 files changed, 582 insertions(+), 132 deletions(-) create mode 100644 src/IKVM.Runtime/Accessors/Com/Sun/Crypto/Provider/AESCryptAccessor.cs create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.X86.cs create mode 100644 src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs diff --git a/src/IKVM.Java/map.xml b/src/IKVM.Java/map.xml index f3fe1cc77..5a55e04a2 100644 --- a/src/IKVM.Java/map.xml +++ b/src/IKVM.Java/map.xml @@ -1639,7 +1639,7 @@ - + @@ -1647,14 +1647,14 @@ - - + + - + @@ -1662,8 +1662,8 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IKVM.Runtime/Accessors/Com/Sun/Crypto/Provider/AESCryptAccessor.cs b/src/IKVM.Runtime/Accessors/Com/Sun/Crypto/Provider/AESCryptAccessor.cs new file mode 100644 index 000000000..a5c6ff726 --- /dev/null +++ b/src/IKVM.Runtime/Accessors/Com/Sun/Crypto/Provider/AESCryptAccessor.cs @@ -0,0 +1,13 @@ +namespace IKVM.Runtime.Accessors.Com.Sun.Crypto.Provider; + +#if !(FIRST_PASS || EXPORTER || IMPORTER) + +internal sealed class AESCryptAccessor(AccessorTypeResolver resolver) + : Accessor(resolver, "com.sun.crypto.provider.AESCrypt") +{ + private FieldAccessor k; + + public int[] K(com.sun.crypto.provider.AESCrypt self) => GetField(ref k, "K").GetValue(self); +} + +#endif \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs index 485b10751..205d070d1 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs @@ -7,147 +7,157 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider.X86; -internal static class AESCrypt +internal abstract partial class AESCrypt { - public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; + public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported; - private static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; + protected static ReadOnlySpan KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]; - private static Vector128 LoadKey(ReadOnlySpan key, nuint offset, Vector128? shuffle_mask = null) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void DecryptBlock(ReadOnlySpan from, Span to, ReadOnlySpan key) { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 + Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmmdest = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); - shuffle_mask ??= Vector128.Create(KeyShuffleMask).AsByte(); + var xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask), 0).AsByte(); + var xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from)); #else - var xmmdest = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); - shuffle_mask ??= Vector128Polyfill.Create(KeyShuffleMask).AsByte(); + var xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask), 0).AsByte(); + var xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from)); #endif - return Ssse3.Shuffle(xmmdest, shuffle_mask.Value); + xmm_temp1 = LoadKey(key, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(key, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(key, 0x40, xmm_key_shuf_mask); + + xmm_result = Sse2.Xor(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey(key, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(key, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(key, 0x80, xmm_key_shuf_mask); + + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); + + xmm_temp1 = LoadKey(key, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0xa0, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(key, 0x00, xmm_key_shuf_mask); + + if (key.Length == 44) + { + goto doLast; + } + + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey(key, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0xc0, xmm_key_shuf_mask); + + if (key.Length == 52) + { + goto doLast; + } + + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey(key, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0xe0, xmm_key_shuf_mask); + + doLast:; + xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); + xmm_result.CopyTo(to); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void EncryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) + public static void EncryptBlock(ReadOnlySpan from, Span to, ReadOnlySpan key) { // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277 Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in); + var xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); + var xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from)); #else - var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in); + var xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); + var xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from)); #endif - xmm_temp1 = LoadKey(K, 0x00, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(key, 0x00, xmm_key_shuf_mask); xmm_result = Sse2.Xor(xmm_result, xmm_temp1); - xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(key, 0x10, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0x20, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(key, 0x30, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(key, 0x40, xmm_key_shuf_mask); xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(key, 0x50, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0x60, xmm_key_shuf_mask); + xmm_temp3 = LoadKey(key, 0x70, xmm_key_shuf_mask); + xmm_temp4 = LoadKey(key, 0x80, xmm_key_shuf_mask); xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); xmm_result = Aes.Encrypt(xmm_result, xmm_temp3); xmm_result = Aes.Encrypt(xmm_result, xmm_temp4); - xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); + xmm_temp1 = LoadKey(key, 0x90, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0xa0, xmm_key_shuf_mask); - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2215,2216 - if (K.Length != 44) + if (key.Length == 44) { - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + goto doLast; + } - xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); - if (K.Length != 52) - { - xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + xmm_temp1 = LoadKey(key, 0xb0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0xc0, xmm_key_shuf_mask); - xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); - } + if (key.Length == 52) + { + goto doLast; } + xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); + xmm_result = Aes.Encrypt(xmm_result, xmm_temp2); + + xmm_temp1 = LoadKey(key, 0xd0, xmm_key_shuf_mask); + xmm_temp2 = LoadKey(key, 0xe0, xmm_key_shuf_mask); + + doLast:; xmm_result = Aes.Encrypt(xmm_result, xmm_temp1); xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2); - xmm_result.CopyTo(@out); + xmm_result.CopyTo(to); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void DecryptBlock(ReadOnlySpan @in, Span @out, ReadOnlySpan K) + protected static Vector128 LoadKey(ReadOnlySpan key, nuint offset, Vector128? shuffle_mask = null) { - // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210 - Vector128 xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4; #if NET8_0_OR_GREATER - var xmm_key_shuf_mask = Vector128.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128.Create(@in); + Vector128 xmm_temp = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); + shuffle_mask ??= Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); #else - var xmm_key_shuf_mask = Vector128Polyfill.Create(KeyShuffleMask).AsByte(); - var xmm_result = Vector128Polyfill.Create(@in); + Vector128 xmm_temp = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(key)), offset); + shuffle_mask ??= Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); #endif - xmm_temp1 = LoadKey(K, 0x10, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x20, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x30, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x40, xmm_key_shuf_mask); - - xmm_result = Sse2.Xor(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); - - xmm_temp1 = LoadKey(K, 0x50, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0x60, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x70, xmm_key_shuf_mask); - xmm_temp4 = LoadKey(K, 0x80, xmm_key_shuf_mask); - - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp3); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp4); - - xmm_temp1 = LoadKey(K, 0x90, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xa0, xmm_key_shuf_mask); - xmm_temp3 = LoadKey(K, 0x00, xmm_key_shuf_mask); - - if (K.Length != 44) - { - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - - xmm_temp1 = LoadKey(K, 0xb0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xc0, xmm_key_shuf_mask); - - if (K.Length != 52) - { - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - - xmm_temp1 = LoadKey(K, 0xd0, xmm_key_shuf_mask); - xmm_temp2 = LoadKey(K, 0xe0, xmm_key_shuf_mask); - } - } - - xmm_result = Aes.Decrypt(xmm_result, xmm_temp1); - xmm_result = Aes.Decrypt(xmm_result, xmm_temp2); - xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3); - xmm_result.CopyTo(@out); + return Ssse3.Shuffle(xmm_temp, shuffle_mask.Value); } } #endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs index aff7643af..d657047bc 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs @@ -8,12 +8,12 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider; internal static class AESCrypt { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER if (X86.AESCrypt.IsSupported) { - X86.AESCrypt.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); + X86.AESCrypt.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); return true; } #endif @@ -22,12 +22,12 @@ public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOf } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) + public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K) { #if NETCOREAPP3_0_OR_GREATER if (X86.AESCrypt.IsSupported) { - X86.AESCrypt.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); + X86.AESCrypt.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K); return true; } #endif diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.X86.cs new file mode 100644 index 000000000..f8d0a781d --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.X86.cs @@ -0,0 +1,312 @@ +#if NETCOREAPP3_0_OR_GREATER +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace IKVM.Java.Externs.com.sun.crypto.provider.X86; + +internal abstract partial class CipherBlockChaining : AESCrypt +{ + const int AESBlockSize = 16; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void DecryptAESCrypt(ReadOnlySpan from, Span to, ReadOnlySpan key, Span rvec, int length) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2568-2720 +#if NET8_0_OR_GREATER + Vector128 xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); +#else + Vector128 xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); +#endif + + const int XMM_REG_NUM_KEY_FIRST = 2; + const int XMM_REG_NUM_KEY_LAST = 7; + const nuint FIRST_NON_REG_KEY_offset = 0x70; + + Span> xmm_key = stackalloc Vector128[6]; + ref Vector128 xmm_key_first = ref MemoryMarshal.GetReference(xmm_key); + + for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x10; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_key[as_XMMRegister(rnum)] = LoadKey(key, (nuint)offset, xmm_key_shuf_mask); + offset += 0x10; + } + + ref byte prev_block_cipher_ptr = ref MemoryMarshal.GetReference(rvec); + + if (key.Length != 44) + { + goto key_192_256; + } + + nuint pos = 0; + singleBlock_loopTop_128: + if (length == 0) + { + goto exit; + } + +#if NET8_0_OR_GREATER + Vector128 xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#else + Vector128 xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_key_first); + for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_result = Aes.Decrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]); + } + + for (var key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xa0; key_offset += 0x10) + { + xmm_result = AesDecKey(xmm_result, key, key_offset); + } + + Vector128 xmm_temp = LoadKey(key, 0x00); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp); +#if NET8_0_OR_GREATER + xmm_temp = Vector128.LoadUnsafe(in prev_block_cipher_ptr); +#else + xmm_temp = Vector128Polyfill.LoadUnsafe(in prev_block_cipher_ptr); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_temp); + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(to), pos); + prev_block_cipher_ptr = ref Unsafe.Add(ref MemoryMarshal.GetReference(from), pos); + pos += AESBlockSize; + length -= AESBlockSize; + goto singleBlock_loopTop_128; + + exit:; + Unsafe.CopyBlockUnaligned(ref MemoryMarshal.GetReference(rvec), ref prev_block_cipher_ptr, 16); + return; + + key_192_256:; + if (key.Length != 52) + { + goto key_256; + } + + pos = 0; + singleBlock_loopTop_192:; +#if NET8_0_OR_GREATER + xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#else + xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_key_first); + for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_result = Aes.Decrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]); + } + + for (var key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xc0; key_offset += 0x10) + { + xmm_result = AesDecKey(xmm_result, key, key_offset); + } + + xmm_temp = LoadKey(key, 0x00); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp); +#if NET8_0_OR_GREATER + xmm_temp = Vector128.LoadUnsafe(in prev_block_cipher_ptr); +#else + xmm_temp = Vector128Polyfill.LoadUnsafe(in prev_block_cipher_ptr); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_temp); + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(to), pos); + prev_block_cipher_ptr = ref Unsafe.Add(ref MemoryMarshal.GetReference(from), pos); pos += AESBlockSize; + length -= AESBlockSize; + if (length != 0) + { + goto singleBlock_loopTop_192; + } + + goto exit; + + key_256:; + pos = 0; + singleBlock_loopTop_256:; +#if NET8_0_OR_GREATER + xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#else + xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_key_first); + for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_result = Aes.Decrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]); + } + + for (var key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xe0; key_offset += 0x10) + { + xmm_result = AesDecKey(xmm_result, key, key_offset); + } + + xmm_temp = LoadKey(key, 0x00); + xmm_result = Aes.DecryptLast(xmm_result, xmm_temp); +#if NET8_0_OR_GREATER + xmm_temp = Vector128.LoadUnsafe(in prev_block_cipher_ptr); +#else + xmm_temp = Vector128Polyfill.LoadUnsafe(in prev_block_cipher_ptr); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_temp); + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(to), pos); + prev_block_cipher_ptr = ref Unsafe.Add(ref MemoryMarshal.GetReference(from), pos); pos += AESBlockSize; + length -= AESBlockSize; + if (length != 0) + { + goto singleBlock_loopTop_256; + } + + goto exit; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void EncryptAESCrypt(ReadOnlySpan from, Span to, ReadOnlySpan key, Span rvec, int length) + { + // ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2410-2549 +#if NET8_0_OR_GREATER + Vector128 xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); +#else + Vector128 xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte(); +#endif + + const int XMM_REG_NUM_KEY_FIRST = 2; + const int XMM_REG_NUM_KEY_LAST = 7; + + Span> xmm_key = stackalloc Vector128[6]; + ref Vector128 xmm_key0 = ref MemoryMarshal.GetReference(xmm_key); + for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x00; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_key[as_XMMRegister(rnum)] = LoadKey(key, (nuint)offset, xmm_key_shuf_mask); + offset += 0x10; + } + +#if NET8_0_OR_GREATER + Vector128 xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(rvec)); +#else + Vector128 xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(rvec)); +#endif + + if (key.Length != 44) + { + goto key_192_256; + } + + nuint pos = 0; + loopTop_128:; +#if NET8_0_OR_GREATER + Vector128 xmm_temp = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#else + Vector128 xmm_temp = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_temp); + xmm_result = Sse2.Xor(xmm_result, xmm_key0); + for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_result = Aes.Encrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]); + } + + for (int key_offset = 0x60; key_offset <= 0x90; key_offset += 0x10) + { + xmm_result = AesEncKey(xmm_result, key, (nuint)key_offset); + } + + xmm_temp = LoadKey(key, 0xa0); + xmm_result = Aes.EncryptLast(xmm_result, xmm_temp); + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(to), pos); + pos += AESBlockSize; + length -= AESBlockSize; + if (length != 0) + { + goto loopTop_128; + } + + exit: + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(rvec)); + return; + + key_192_256:; + if (key.Length != 52) + { + goto key_256; + } + + pos = 0; + loopTop_192:; +#if NET8_0_OR_GREATER + xmm_temp = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#else + xmm_temp = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_temp); + xmm_result = Sse2.Xor(xmm_result, xmm_key0); + for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_result = Aes.Encrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]); + } + + for (nuint key_offset = 0x60; key_offset <= 0xb0; key_offset += 0x10) + { + xmm_result = AesEncKey(xmm_result, key, key_offset); + } + + xmm_temp = LoadKey(key, 0xc0); + xmm_result = Aes.EncryptLast(xmm_result, xmm_temp); + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(to), pos); + pos += AESBlockSize; + length -= AESBlockSize; + if (length != 0) + { + goto loopTop_192; + } + + goto exit; + + key_256:; + pos = 0; + loopTop_256: +#if NET8_0_OR_GREATER + xmm_temp = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#else + xmm_temp = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from), pos); +#endif + xmm_result = Sse2.Xor(xmm_result, xmm_temp); + xmm_result = Sse2.Xor(xmm_result, xmm_key0); + for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) + { + xmm_result = Aes.Encrypt(xmm_result, xmm_key[as_XMMRegister(rnum)]); + } + + for (nuint key_offset = 0x60; key_offset <= 0xd0; key_offset += 0x10) + { + xmm_result = AesEncKey(xmm_result, key, key_offset); + } + + xmm_temp = LoadKey(key, 0xe0); + xmm_result = Aes.EncryptLast(xmm_result, xmm_temp); + xmm_result.StoreUnsafe(ref MemoryMarshal.GetReference(to), pos); + pos += AESBlockSize; + length -= AESBlockSize; + if (length != 0) + { + goto loopTop_256; + } + + goto exit; + } + + private static Vector128 AesDecKey(Vector128 xmmdst, ReadOnlySpan key, nuint offset, Vector128? xmm_shuf_mask = null) + { + return Aes.Decrypt(xmmdst, LoadKey(key, offset, xmm_shuf_mask)); + } + + private static Vector128 AesEncKey(Vector128 xmmdst, ReadOnlySpan key, nuint offset, Vector128? xmm_shuf_mask = null) + { + return Aes.Encrypt(xmmdst, LoadKey(key, offset, xmm_shuf_mask)); + } + + private static int as_XMMRegister(int @in) => @in - 2; +} +#endif \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs new file mode 100644 index 000000000..6c1f0fb8d --- /dev/null +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs @@ -0,0 +1,63 @@ +using IKVM.Runtime; +using IKVM.Runtime.Accessors.Com.Sun.Crypto.Provider; +using System; +using System.Runtime.CompilerServices; + +namespace IKVM.Java.Externs.com.sun.crypto.provider; + +internal static class CipherBlockChaining +{ +#if !FIRST_PASS + private static AESCryptAccessor aesCryptAccessor; + + private static AESCryptAccessor AESCryptAccessor => JVM.Internal.BaseAccessors.Get(ref aesCryptAccessor); +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool DecryptAESCrypt(object self, byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset) + { +#if !FIRST_PASS && NETCOREAPP3_0_OR_GREATER + if (plain == cipher || self is not global::com.sun.crypto.provider.CipherBlockChaining + { + r: { } r, + embeddedCipher: global::com.sun.crypto.provider.AESCrypt aes + }) + { + return false; + } + + var k = AESCryptAccessor.K(aes); + + if (X86.AESCrypt.IsSupported) + { + X86.CipherBlockChaining.EncryptAESCrypt(cipher.AsSpan(cipherOffset), plain.AsSpan(plainOffset), k, r, cipherLen); + return true; + } +#endif + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EncryptAESCrypt(object self, byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) + { +#if !FIRST_PASS && NETCOREAPP3_0_OR_GREATER + if (self is not global::com.sun.crypto.provider.CipherBlockChaining + { + r: { } r, + embeddedCipher: global::com.sun.crypto.provider.AESCrypt aes + }) + { + return false; + } + + var k = AESCryptAccessor.K(aes); + + if (X86.AESCrypt.IsSupported) + { + X86.CipherBlockChaining.EncryptAESCrypt(plain.AsSpan(plainOffset), cipher.AsSpan(cipherOffset), k, r, plainLen); + return true; + } +#endif + return false; + } +} \ No newline at end of file diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs index 516781d16..b1c6125e2 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/GHASH.X86.cs @@ -9,7 +9,7 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider.X86; internal static class GHASH { - public static bool IsSupported => Pclmulqdq.IsSupported && Ssse3.IsSupported && Sse2.IsSupported; + public static bool IsSupported => Pclmulqdq.IsSupported && Ssse3.IsSupported; private static ReadOnlySpan ByteSwapMask => [0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203]; @@ -30,24 +30,24 @@ public static void ProcessBlocks(ReadOnlySpan data, int blocks, Span xmm_temp7; #if NET8_0_OR_GREATER - xmm_temp0 = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(state)), 0); - xmm_temp0 = Ssse3.Shuffle(xmm_temp0.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); - xmm_temp1 = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(subH)), 0); - xmm_temp1 = Ssse3.Shuffle(xmm_temp1.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); + xmm_temp0 = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(state)).AsInt32(); + xmm_temp0 = Ssse3.Shuffle(xmm_temp0.AsByte(), Vector128.LoadUnsafe(in MemoryMarshal.GetReference(LongSwapMask)).AsByte()).AsInt32(); + xmm_temp1 = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(subH)).AsInt32(); + xmm_temp1 = Ssse3.Shuffle(xmm_temp1.AsByte(), Vector128.LoadUnsafe(in MemoryMarshal.GetReference(LongSwapMask)).AsByte()).AsInt32(); #else - xmm_temp0 = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(state)), 0); - xmm_temp0 = Ssse3.Shuffle(xmm_temp0.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); - xmm_temp1 = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(subH)), 0); - xmm_temp1 = Ssse3.Shuffle(xmm_temp1.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))).AsInt32(); + xmm_temp0 = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(state)).AsInt32(); + xmm_temp0 = Ssse3.Shuffle(xmm_temp0.AsByte(), Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(LongSwapMask)).AsByte()).AsInt32(); + xmm_temp1 = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(subH)).AsInt32(); + xmm_temp1 = Ssse3.Shuffle(xmm_temp1.AsByte(), Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(LongSwapMask)).AsByte()).AsInt32(); #endif ghash_loop: #if NET8_0_OR_GREATER - xmm_temp2 = Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(data)), 0); - xmm_temp2 = Ssse3.Shuffle(xmm_temp2.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(ByteSwapMask)))).AsInt32(); + xmm_temp2 = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(data)).AsInt32(); + xmm_temp2 = Ssse3.Shuffle(xmm_temp2.AsByte(), Vector128.LoadUnsafe(in MemoryMarshal.GetReference(ByteSwapMask)).AsByte()).AsInt32(); #else - xmm_temp2 = Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(data)), 0); - xmm_temp2 = Ssse3.Shuffle(xmm_temp2.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(ByteSwapMask)))).AsInt32(); + xmm_temp2 = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(data)).AsInt32(); + xmm_temp2 = Ssse3.Shuffle(xmm_temp2.AsByte(), Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(ByteSwapMask)).AsByte()).AsInt32(); #endif xmm_temp0 = Sse2.Xor(xmm_temp0, xmm_temp2); @@ -118,10 +118,10 @@ public static void ProcessBlocks(ReadOnlySpan data, int blocks, Span exit:; #if NET8_0_OR_GREATER - Ssse3.Shuffle(xmm_temp6.AsByte(), Vector128.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))) + Ssse3.Shuffle(xmm_temp6.AsByte(), Vector128.LoadUnsafe(in MemoryMarshal.GetReference(LongSwapMask)).AsByte()) .AsInt64().CopyTo(state); #else - Ssse3.Shuffle(xmm_temp6.AsByte(), Vector128Polyfill.LoadUnsafe(in Unsafe.As(ref MemoryMarshal.GetReference(LongSwapMask)))) + Ssse3.Shuffle(xmm_temp6.AsByte(), Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(LongSwapMask)).AsByte()) .AsInt64().CopyTo(state); #endif } diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs index 92b4b07af..5a3647532 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/Vector128Polyfill.cs @@ -1,4 +1,4 @@ -#if NETCOREAPP3_0_OR_GREATER && !(NET8_0_OR_GREATER) +#if NETCOREAPP3_0_OR_GREATER && !NET8_0_OR_GREATER using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -8,6 +8,28 @@ namespace IKVM.Java.Externs.com.sun.crypto.provider; internal static class Vector128Polyfill { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyTo(this Vector128 vector, Span destination) where T : struct + { + if (destination.Length < Vector128.Count) + { + throw new ArgumentException(null, nameof(destination)); + } + + Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Create(ReadOnlySpan values) where T : struct + { + if (values.Length < Vector128.Count) + { + throw new ArgumentOutOfRangeException(nameof(values)); + } + + return Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 LoadUnsafe(ref readonly T source) where T : struct { @@ -27,25 +49,21 @@ public static Vector128 LoadUnsafe(ref readonly T source, nuint elementOff } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Create(ReadOnlySpan values) where T : struct + public static void StoreUnsafe(this Vector128 source, ref T destination) where T : struct { - if (values.Length < Vector128.Count) - { - throw new ArgumentOutOfRangeException(nameof(values)); - } - - return Unsafe.ReadUnaligned>(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + // Use with caution. + // Supports blittable primitives only. + ref byte address = ref Unsafe.As(ref destination); + Unsafe.WriteUnaligned(ref address, source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void CopyTo(this Vector128 vector, Span destination) where T : struct + public static void StoreUnsafe(this Vector128 source, ref T destination, nuint elementOffset) where T : struct { - if (destination.Length < Vector128.Count) - { - throw new ArgumentException(null, nameof(destination)); - } - - Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), vector); + // Use with caution. + // Supports blittable primitives only. + destination = ref Unsafe.Add(ref destination, (nint)elementOffset); + Unsafe.WriteUnaligned(ref Unsafe.As(ref destination), source); } } #endif From 6223e88efa39e6fdbf12b08bb34d41ea0a4dd9b7 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Wed, 15 Jan 2025 13:01:00 +0100 Subject: [PATCH 13/13] Fix Copy-Paste --- .../Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs index 6c1f0fb8d..f9350406b 100644 --- a/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs +++ b/src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/CipherBlockChaining.cs @@ -30,7 +30,7 @@ public static bool DecryptAESCrypt(object self, byte[] cipher, int cipherOffset, if (X86.AESCrypt.IsSupported) { - X86.CipherBlockChaining.EncryptAESCrypt(cipher.AsSpan(cipherOffset), plain.AsSpan(plainOffset), k, r, cipherLen); + X86.CipherBlockChaining.DecryptAESCrypt(cipher.AsSpan(cipherOffset), plain.AsSpan(plainOffset), k, r, cipherLen); return true; } #endif