Skip to content

Commit 6f6d70d

Browse files
authored
Merge pull request #650 from iterate-ch/feature/390-aes
AES HW Intrinsics (X86)
2 parents 344a1f5 + 6223e88 commit 6f6d70d

File tree

9 files changed

+889
-0
lines changed

9 files changed

+889
-0
lines changed

src/IKVM.Java/map.xml

+82
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,88 @@
16381638
</body>
16391639
</method>
16401640
</class>
1641+
<class name="com.sun.crypto.provider.AESCrypt">
1642+
<method name="decryptBlock" sig="([BI[BI)V">
1643+
<prologue>
1644+
<ldarg_1 />
1645+
<ldarg_2 />
1646+
<ldarg_3 />
1647+
<ldarg_s argNum="4" />
1648+
<ldarg_0 />
1649+
<ldfld class="com.sun.crypto.provider.AESCrypt" name="K" sig="[I" />
1650+
<!-- bool AESCrypt.DecryptBlock(byte[] in, int inOffset, byte[] out, int outOffset, int[] K) -->
1651+
<call type="IKVM.Java.Externs.com.sun.crypto.provider.AESCrypt" name="DecryptBlock" sig="([BI[BI[I)Z" />
1652+
<brfalse name="continue" />
1653+
<ret />
1654+
<label name="continue" />
1655+
</prologue>
1656+
</method>
1657+
<method name="encryptBlock" sig="([BI[BI)V">
1658+
<prologue>
1659+
<ldarg_1 />
1660+
<ldarg_2 />
1661+
<ldarg_3 />
1662+
<ldarg_s argNum="4" />
1663+
<ldarg_0 />
1664+
<ldfld class="com.sun.crypto.provider.AESCrypt" name="K" sig="[I" />
1665+
<!-- bool AESCrypt.EncryptBlock(byte[] in, int inOffset, byte[] out, int outOffset, int[] K) -->
1666+
<call type="IKVM.Java.Externs.com.sun.crypto.provider.AESCrypt" name="EncryptBlock" sig="([BI[BI[I)Z" />
1667+
<brfalse name="continue" />
1668+
<ret />
1669+
<label name="continue" />
1670+
</prologue>
1671+
</method>
1672+
</class>
1673+
<class name="com.sun.crypto.provider.GHASH">
1674+
<method name="processBlocks" sig="([BII[J[J)V">
1675+
<prologue>
1676+
<ldarg_0 />
1677+
<ldarg_1 />
1678+
<ldarg_2 />
1679+
<ldarg_3 />
1680+
<ldarg_s argNum="4" />
1681+
<!-- bool GHASH.ProcessBlocks(byte[] data, int inOffs, int blocks, long[] state, long[] subH) -->
1682+
<call type="IKVM.Java.Externs.com.sun.crypto.provider.GHASH" name="ProcessBlocks" sig="([BII[J[J)Z" />
1683+
<brfalse name="continue" />
1684+
<ret />
1685+
<label name="continue" />
1686+
</prologue>
1687+
</method>
1688+
</class>
1689+
<class name="com.sun.crypto.provider.CipherBlockChaining">
1690+
<method name="implDecrypt" sig="([BII[BI)I">
1691+
<prologue>
1692+
<ldarg_0 />
1693+
<ldarg_1 />
1694+
<ldarg_2 />
1695+
<ldarg_3 />
1696+
<ldarg_s argNum="4" />
1697+
<ldarg_s argNum="5" />
1698+
<!-- bool CipherBlockChaining.DecryptAESCrypt(object self, byte[] cipher, int cipherOffset, int cipherLen, byte[] plain, int plainOffset, ) -->
1699+
<call type="IKVM.Java.Externs.com.sun.crypto.provider.CipherBlockChaining" name="DecryptAESCrypt" sig="(Ljava.lang.Object;[BII[BI)Z" />
1700+
<brfalse name="continue" />
1701+
<ldarg_3 />
1702+
<ret />
1703+
<label name="continue" />
1704+
</prologue>
1705+
</method>
1706+
<method name="implEncrypt" sig="([BII[BI)I">
1707+
<prologue>
1708+
<ldarg_0 />
1709+
<ldarg_1 />
1710+
<ldarg_2 />
1711+
<ldarg_3 />
1712+
<ldarg_s argNum="4" />
1713+
<ldarg_s argNum="5" />
1714+
<!-- bool CipherBlockChaining.EncryptAESCrypt(object self, byte[] plain, int plainOffset, int plainLen, byte[] cipher, int cipherOffset) -->
1715+
<call type="IKVM.Java.Externs.com.sun.crypto.provider.CipherBlockChaining" name="EncryptAESCrypt" sig="(Ljava.lang.Object;[BII[BI)Z" />
1716+
<brfalse name="continue" />
1717+
<ldarg_3 />
1718+
<ret />
1719+
<label name="continue" />
1720+
</prologue>
1721+
</method>
1722+
</class>
16411723
<!-- This is where the "native" helper methods start -->
16421724
<class name="ikvm.lang.CIL">
16431725
<method name="unbox_byte" sig="(Ljava.lang.Object;)B">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace IKVM.Runtime.Accessors.Com.Sun.Crypto.Provider;
2+
3+
#if !(FIRST_PASS || EXPORTER || IMPORTER)
4+
5+
internal sealed class AESCryptAccessor(AccessorTypeResolver resolver)
6+
: Accessor<com.sun.crypto.provider.AESCrypt>(resolver, "com.sun.crypto.provider.AESCrypt")
7+
{
8+
private FieldAccessor<com.sun.crypto.provider.AESCrypt, int[]> k;
9+
10+
public int[] K(com.sun.crypto.provider.AESCrypt self) => GetField(ref k, "K").GetValue(self);
11+
}
12+
13+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#if NETCOREAPP3_0_OR_GREATER
2+
using System;
3+
using System.Runtime.CompilerServices;
4+
using System.Runtime.InteropServices;
5+
using System.Runtime.Intrinsics;
6+
using System.Runtime.Intrinsics.X86;
7+
8+
namespace IKVM.Java.Externs.com.sun.crypto.provider.X86;
9+
10+
internal abstract partial class AESCrypt
11+
{
12+
public static bool IsSupported => Aes.IsSupported && Ssse3.IsSupported;
13+
14+
protected static ReadOnlySpan<int> KeyShuffleMask => [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f];
15+
16+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
17+
public static void DecryptBlock(ReadOnlySpan<byte> from, Span<byte> to, ReadOnlySpan<int> key)
18+
{
19+
// ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:3125-3210
20+
Vector128<byte> xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4;
21+
#if NET8_0_OR_GREATER
22+
var xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask), 0).AsByte();
23+
var xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from));
24+
#else
25+
var xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask), 0).AsByte();
26+
var xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from));
27+
#endif
28+
29+
xmm_temp1 = LoadKey(key, 0x10, xmm_key_shuf_mask);
30+
xmm_temp2 = LoadKey(key, 0x20, xmm_key_shuf_mask);
31+
xmm_temp3 = LoadKey(key, 0x30, xmm_key_shuf_mask);
32+
xmm_temp4 = LoadKey(key, 0x40, xmm_key_shuf_mask);
33+
34+
xmm_result = Sse2.Xor(xmm_result, xmm_temp1);
35+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp2);
36+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp3);
37+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp4);
38+
39+
xmm_temp1 = LoadKey(key, 0x50, xmm_key_shuf_mask);
40+
xmm_temp2 = LoadKey(key, 0x60, xmm_key_shuf_mask);
41+
xmm_temp3 = LoadKey(key, 0x70, xmm_key_shuf_mask);
42+
xmm_temp4 = LoadKey(key, 0x80, xmm_key_shuf_mask);
43+
44+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp1);
45+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp2);
46+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp3);
47+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp4);
48+
49+
xmm_temp1 = LoadKey(key, 0x90, xmm_key_shuf_mask);
50+
xmm_temp2 = LoadKey(key, 0xa0, xmm_key_shuf_mask);
51+
xmm_temp3 = LoadKey(key, 0x00, xmm_key_shuf_mask);
52+
53+
if (key.Length == 44)
54+
{
55+
goto doLast;
56+
}
57+
58+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp1);
59+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp2);
60+
61+
xmm_temp1 = LoadKey(key, 0xb0, xmm_key_shuf_mask);
62+
xmm_temp2 = LoadKey(key, 0xc0, xmm_key_shuf_mask);
63+
64+
if (key.Length == 52)
65+
{
66+
goto doLast;
67+
}
68+
69+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp1);
70+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp2);
71+
72+
xmm_temp1 = LoadKey(key, 0xd0, xmm_key_shuf_mask);
73+
xmm_temp2 = LoadKey(key, 0xe0, xmm_key_shuf_mask);
74+
75+
doLast:;
76+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp1);
77+
xmm_result = Aes.Decrypt(xmm_result, xmm_temp2);
78+
xmm_result = Aes.DecryptLast(xmm_result, xmm_temp3);
79+
xmm_result.CopyTo(to);
80+
}
81+
82+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
83+
public static void EncryptBlock(ReadOnlySpan<byte> from, Span<byte> to, ReadOnlySpan<int> key)
84+
{
85+
// ext\openjdk\hotspot\src\cpu\x86\vm\stubGenerator_x86_32.cpp:2189-2277
86+
Vector128<byte> xmm_temp1, xmm_temp2, xmm_temp3, xmm_temp4;
87+
#if NET8_0_OR_GREATER
88+
var xmm_key_shuf_mask = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
89+
var xmm_result = Vector128.LoadUnsafe(in MemoryMarshal.GetReference(from));
90+
#else
91+
var xmm_key_shuf_mask = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
92+
var xmm_result = Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(from));
93+
#endif
94+
95+
xmm_temp1 = LoadKey(key, 0x00, xmm_key_shuf_mask);
96+
xmm_result = Sse2.Xor(xmm_result, xmm_temp1);
97+
98+
xmm_temp1 = LoadKey(key, 0x10, xmm_key_shuf_mask);
99+
xmm_temp2 = LoadKey(key, 0x20, xmm_key_shuf_mask);
100+
xmm_temp3 = LoadKey(key, 0x30, xmm_key_shuf_mask);
101+
xmm_temp4 = LoadKey(key, 0x40, xmm_key_shuf_mask);
102+
103+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp1);
104+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp2);
105+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp3);
106+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp4);
107+
108+
xmm_temp1 = LoadKey(key, 0x50, xmm_key_shuf_mask);
109+
xmm_temp2 = LoadKey(key, 0x60, xmm_key_shuf_mask);
110+
xmm_temp3 = LoadKey(key, 0x70, xmm_key_shuf_mask);
111+
xmm_temp4 = LoadKey(key, 0x80, xmm_key_shuf_mask);
112+
113+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp1);
114+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp2);
115+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp3);
116+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp4);
117+
118+
xmm_temp1 = LoadKey(key, 0x90, xmm_key_shuf_mask);
119+
xmm_temp2 = LoadKey(key, 0xa0, xmm_key_shuf_mask);
120+
121+
if (key.Length == 44)
122+
{
123+
goto doLast;
124+
}
125+
126+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp1);
127+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp2);
128+
129+
xmm_temp1 = LoadKey(key, 0xb0, xmm_key_shuf_mask);
130+
xmm_temp2 = LoadKey(key, 0xc0, xmm_key_shuf_mask);
131+
132+
if (key.Length == 52)
133+
{
134+
goto doLast;
135+
}
136+
137+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp1);
138+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp2);
139+
140+
xmm_temp1 = LoadKey(key, 0xd0, xmm_key_shuf_mask);
141+
xmm_temp2 = LoadKey(key, 0xe0, xmm_key_shuf_mask);
142+
143+
doLast:;
144+
xmm_result = Aes.Encrypt(xmm_result, xmm_temp1);
145+
xmm_result = Aes.EncryptLast(xmm_result, xmm_temp2);
146+
xmm_result.CopyTo(to);
147+
}
148+
149+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
150+
protected static Vector128<byte> LoadKey(ReadOnlySpan<int> key, nuint offset, Vector128<byte>? shuffle_mask = null)
151+
{
152+
#if NET8_0_OR_GREATER
153+
Vector128<byte> xmm_temp = Vector128.LoadUnsafe(in Unsafe.As<int, byte>(ref MemoryMarshal.GetReference(key)), offset);
154+
shuffle_mask ??= Vector128.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
155+
#else
156+
Vector128<byte> xmm_temp = Vector128Polyfill.LoadUnsafe(in Unsafe.As<int, byte>(ref MemoryMarshal.GetReference(key)), offset);
157+
shuffle_mask ??= Vector128Polyfill.LoadUnsafe(in MemoryMarshal.GetReference(KeyShuffleMask)).AsByte();
158+
#endif
159+
160+
return Ssse3.Shuffle(xmm_temp, shuffle_mask.Value);
161+
}
162+
}
163+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using IKVM.Attributes;
2+
using System;
3+
using System.Runtime.CompilerServices;
4+
5+
namespace IKVM.Java.Externs.com.sun.crypto.provider;
6+
7+
[HideFromJava]
8+
internal static class AESCrypt
9+
{
10+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
11+
public static bool DecryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K)
12+
{
13+
#if NETCOREAPP3_0_OR_GREATER
14+
if (X86.AESCrypt.IsSupported)
15+
{
16+
X86.AESCrypt.DecryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K);
17+
return true;
18+
}
19+
#endif
20+
21+
return false;
22+
}
23+
24+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
25+
public static bool EncryptBlock(byte[] @in, int inOffset, byte[] @out, int outOffset, int[] K)
26+
{
27+
#if NETCOREAPP3_0_OR_GREATER
28+
if (X86.AESCrypt.IsSupported)
29+
{
30+
X86.AESCrypt.EncryptBlock(@in.AsSpan(inOffset), @out.AsSpan(outOffset), K);
31+
return true;
32+
}
33+
#endif
34+
35+
return false;
36+
}
37+
}

0 commit comments

Comments
 (0)