ikvm icon indicating copy to clipboard operation
ikvm copied to clipboard

Port AES-NI from Hotspot to IKVM

Open AliveDevil opened this issue 2 years ago • 3 comments

There are some intrinsics in JDK, that allow runtime swapping of class implementations. AES-NI would allow getting ikvmnet from 16 MByte/s (128 MBit/s) up to JDK-level (Gigabit, beyond) in AES-scenarios. This heavily limits the usage in high-bandwidth encrypted data transfers (HTTP, FTP, etc.). An IKVM-fork got more bandwidth, than ikvmnet, reasons are unclear, for now: iterate-ch/cyberduck#14909

IKVM is currently targeting x86, x64, aarch64 and arm.

Ref implementation, against jdk8u92. x86: https://github.com/openjdk/jdk8u/blob/jdk8u92-b34/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp#L2189 x64: https://github.com/openjdk/jdk8u/blob/jdk8u92-b34/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp#L3031

With JDK8u312 aarch64 has been added: arm64: https://github.com/openjdk/jdk8u/blob/jdk8u312-ga/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp#L2606

JDK8 doesn't have an implementation for AES-NI in arm, this would require sourcing the native implementation from e.g. jdk9: https://github.com/openjdk/jdk/blob/jdk-9%2B150/hotspot/src/cpu/arm/vm/stubRoutinesCrypto_arm.cpp#L120

This could probably be replaced with regular PInvoke on IKVM-side, and simple implementations without the stub-magic in C.

Stubbing is performed in vmSymbols-file: https://github.com/openjdk/jdk8u/blob/jdk8u92-b34/hotspot/src/share/vm/classfile/vmSymbols.hpp#L819-L833

PInvoke signature could look like:

void com_sun_crypto_provider_aescrypt_encryptBlock(byte*, int, byte*, int);
void com_sun_crypto_provider_aescrypt_decryptBlock(byte*, int, byte*, int);

This would need detecting CPU-features in runtime and selecting appropriate implementation (AES-NI or Java) based on that.

As we now have native library-support, we could look at adding this to libjava/libjvm.

AliveDevil avatar Jul 19 '23 10:07 AliveDevil

Research brought up: Slowest path in IKVM is com.sun.crypto.provider.GHASH.update(uint8[], int, int). This lead to finding this: https://github.com/openjdk/jdk8u/blob/jdk8u312-ga/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp#L3664 Which got added as recently as 8u242. Need to port GHash intrinsics as well then.

AliveDevil avatar Jul 19 '23 12:07 AliveDevil

Discussion around this resolved to this:

  • For FX add bcrypt PInvoke on Windows, add intrinsic wrapper to encryptBlock, decryptBlock of both aes and cbc
  • For .NET Core we can amend AESCrypt with map.xml to include an additional field, where we can store an Aes-instance (as obtained from Aes.Create, AesGcm.Create, AesCcm.Create)
    • This then replaces the Java implementation

AliveDevil avatar Jul 20 '23 08:07 AliveDevil

Intrinsics: com/sun/crypto/provider/AESCrypt, methods

  • encryptBlock (impl: _aescrypt_encryptBlock)
  • decryptBlock (impl: _aescrypt_decryptBlock)

com/sun/crypto/provider/CipherBlockChaining, methods:

  • encrypt (impl: _cipherBlockChaining_encryptAESCrypt)
  • decrypt (impl: _cipherBlockChaining_decryptAESCrypt)

AliveDevil avatar Jul 28 '23 09:07 AliveDevil