Skip to content

Commit

Permalink
Merge pull request #650 from iterate-ch/feature/390-aes
Browse files Browse the repository at this point in the history
AES HW Intrinsics (X86)
  • Loading branch information
wasabii authored Jan 15, 2025
2 parents 344a1f5 + 6223e88 commit 6f6d70d
Show file tree
Hide file tree
Showing 9 changed files with 889 additions and 0 deletions.
82 changes: 82 additions & 0 deletions src/IKVM.Java/map.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,88 @@
</body>
</method>
</class>
<class name="com.sun.crypto.provider.AESCrypt">
<method name="decryptBlock" sig="([BI[BI)V">
<prologue>
<ldarg_1 />
<ldarg_2 />
<ldarg_3 />
<ldarg_s argNum="4" />
<ldarg_0 />
<ldfld class="com.sun.crypto.provider.AESCrypt" name="K" sig="[I" />
<!-- bool AESCrypt.DecryptBlock(byte[] in, int inOffset, byte[] out, int outOffset, int[] K) -->
<call type="IKVM.Java.Externs.com.sun.crypto.provider.AESCrypt" name="DecryptBlock" sig="([BI[BI[I)Z" />
<brfalse name="continue" />
<ret />
<label name="continue" />
</prologue>
</method>
<method name="encryptBlock" sig="([BI[BI)V">
<prologue>
<ldarg_1 />
<ldarg_2 />
<ldarg_3 />
<ldarg_s argNum="4" />
<ldarg_0 />
<ldfld class="com.sun.crypto.provider.AESCrypt" name="K" sig="[I" />
<!-- bool AESCrypt.EncryptBlock(byte[] in, int inOffset, byte[] out, int outOffset, int[] K) -->
<call type="IKVM.Java.Externs.com.sun.crypto.provider.AESCrypt" name="EncryptBlock" sig="([BI[BI[I)Z" />
<brfalse name="continue" />
<ret />
<label name="continue" />
</prologue>
</method>
</class>
<class name="com.sun.crypto.provider.GHASH">
<method name="processBlocks" sig="([BII[J[J)V">
<prologue>
<ldarg_0 />
<ldarg_1 />
<ldarg_2 />
<ldarg_3 />
<ldarg_s argNum="4" />
<!-- bool GHASH.ProcessBlocks(byte[] data, int inOffs, int blocks, long[] state, long[] subH) -->
<call type="IKVM.Java.Externs.com.sun.crypto.provider.GHASH" name="ProcessBlocks" sig="([BII[J[J)Z" />
<brfalse name="continue" />
<ret />
<label name="continue" />
</prologue>
</method>
</class>
<class name="com.sun.crypto.provider.CipherBlockChaining">
<method name="implDecrypt" sig="([BII[BI)I">
<prologue>
<ldarg_0 />
<ldarg_1 />
<ldarg_2 />
<ldarg_3 />
<ldarg_s argNum="4" />
<ldarg_s argNum="5" />
<!-- bool CipherBlockChaining.DecryptAESCrypt(object self, byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset, ) -->
<call type="IKVM.Java.Externs.com.sun.crypto.provider.CipherBlockChaining" name="DecryptAESCrypt" sig="(Ljava.lang.Object;[BII[BI)Z" />
<brfalse name="continue" />
<ldarg_3 />
<ret />
<label name="continue" />
</prologue>
</method>
<method name="implEncrypt" sig="([BII[BI)I">
<prologue>
<ldarg_0 />
<ldarg_1 />
<ldarg_2 />
<ldarg_3 />
<ldarg_s argNum="4" />
<ldarg_s argNum="5" />
<!-- bool CipherBlockChaining.EncryptAESCrypt(object self, byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) -->
<call type="IKVM.Java.Externs.com.sun.crypto.provider.CipherBlockChaining" name="EncryptAESCrypt" sig="(Ljava.lang.Object;[BII[BI)Z" />
<brfalse name="continue" />
<ldarg_3 />
<ret />
<label name="continue" />
</prologue>
</method>
</class>
<!-- This is where the "native" helper methods start -->
<class name="ikvm.lang.CIL">
<method name="unbox_byte" sig="(Ljava.lang.Object;)B">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace IKVM.Runtime.Accessors.Com.Sun.Crypto.Provider;

#if !(FIRST_PASS || EXPORTER || IMPORTER)

internal sealed class AESCryptAccessor(AccessorTypeResolver resolver)
: Accessor<com.sun.crypto.provider.AESCrypt>(resolver, "com.sun.crypto.provider.AESCrypt")
{
private FieldAccessor<com.sun.crypto.provider.AESCrypt, int[]> k;

public int[] K(com.sun.crypto.provider.AESCrypt self) => GetField(ref k, "K").GetValue(self);
}

#endif
163 changes: 163 additions & 0 deletions src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.X86.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#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 AESCrypt
{
public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported;

protected static ReadOnlySpan<int> KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f];

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DecryptBlock(ReadOnlySpan<byte> from, Span<byte> to, ReadOnlySpan<int> key)
{
// ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210
Vector128<byte> xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4;
#if NET8_0_OR_GREATER
var xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask), 0).AsByte();
var xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from));
#else
var xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask), 0).AsByte();
var xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from));
#endif

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<byte> from, Span<byte> to, ReadOnlySpan<int> key)
{
// ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277
Vector128<byte> xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4;
#if NET8_0_OR_GREATER
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.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
var xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from));
#endif

xmm_temp1 = LoadKey(key, 0x00, xmm_key_shuf_mask);
xmm_result = Sse2.Xor(xmm_result, xmm_temp1);

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(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(key, 0x90, xmm_key_shuf_mask);
xmm_temp2 = LoadKey(key, 0xa0, xmm_key_shuf_mask);

if (key.Length == 44)
{
goto doLast;
}

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);

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(to);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static Vector128<byte> LoadKey(ReadOnlySpan<int> key, nuint offset, Vector128<byte>? shuffle_mask = null)
{
#if NET8_0_OR_GREATER
Vector128<byte> xmm_temp = Vector128.LoadUnsafe(in Unsafe.As<int, byte>(ref MemoryMarshal.GetReference(key)), offset);
shuffle_mask ??= Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
#else
Vector128<byte> xmm_temp = Vector128Polyfill.LoadUnsafe(in Unsafe.As<int, byte>(ref MemoryMarshal.GetReference(key)), offset);
shuffle_mask ??= Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
#endif

return Ssse3.Shuffle(xmm_temp, shuffle_mask.Value);
}
}
#endif
37 changes: 37 additions & 0 deletions src/IKVM.Runtime/Java/Externs/com/sun/crypto/provider/AESCrypt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using IKVM.Attributes;
using System;
using System.Runtime.CompilerServices;

namespace IKVM.Java.Externs.com.sun.crypto.provider;

[HideFromJava]
internal static class AESCrypt
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K);
return true;
}
#endif

return false;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
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.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K);
return true;
}
#endif

return false;
}
}
Loading

0 comments on commit 6f6d70d

Please sign in to comment.