Java加密比较:SunJCE是否使用本机代码?

问题描述 投票:0回答:1

我编写了一个测试来比较一些Java加密提供程序的性能(粘贴在下面)。我很惊讶地发现SunJCE实现最快,因为其他人(至少Apache Commons Crypto)依赖于本机openssl实现。

  1. SunJCE是否也使用本机实现?
  2. 这个测试是否存在问题,这会给我错误/误导性的结果?
// Nss installed on mac via "brew install nss"
fun getProviders(): List<Provider> {
    return listOf(
        Security.getProvider("SunJCE"),
        sun.security.pkcs11.SunPKCS11(
            "--name=CryptoBenchmark\\n"
                    + "nssDbMode=noDb\\n"
                    + "nssLibraryDirectory=/usr/local/opt/nss/lib/\\n"
                    + "attributes=compatibility"),
        BouncyCastleProvider()
    )
}

fun blockCipherTests(providers: List<Provider>) {
    val ciphers = providers.map {
        try {
            Cipher.getInstance("AES/CTR/NoPadding", it)
        } catch (t: Throwable) {
            println("Error getting cipher from provider $it: $t")
            throw t
        }
    }

    val key = SecretKeySpec(getUTF8Bytes("1234567890123456"),"AES");
    val iv = IvParameterSpec(getUTF8Bytes("1234567890123456"));
    val random = Random()

    ciphers.forEach {
        it.init(Cipher.ENCRYPT_MODE, key)
    }

    // Crypto commons doesn't implement the provider interface(?) so instantiate that cipher separately
    val properties = Properties().apply {
        setProperty(CryptoCipherFactory.CLASSES_KEY, CryptoCipherFactory.CipherProvider.OPENSSL.getClassName());
    }
    val apacheCommonsCipher = Utils.getCipherInstance("AES/CTR/NoPadding", properties)
    apacheCommonsCipher.init(Cipher.ENCRYPT_MODE, key, iv)


    val data = ByteArray(1500)
    val out = ByteArray(1500)
    random.nextBytes(data)
    repeat (10) {
        ciphers.forEach { cipher ->
            val time = measureNanoTime {
                repeat(100) {
                    cipher.doFinal(data)
                }
            }
            println("Cipher ${cipher.provider} took ${time / 100} nanos/run")
        }
        // Run the apache test separately
        val time = measureNanoTime {
            repeat(100) {
                apacheCommonsCipher.doFinal(data, 0, 1000, out, 0)
            }
        }
        println("Cipher apache took ${time / 100} nanos/run")

        println("====================================")
    }
}

fun main() {
    val providers = getProviders()

    println(providers)

    blockCipherTests(providers)
}
java encryption jce
1个回答
0
投票

是的,它确实。不,它没有。

AES-NI通过Java内在函数使用,它通过AES的本机实现替换字节代码。因此,尽管您不会直接调用AES-NI指令,但Java代码中的doFinal调用将在某些时候使用硬件加速。因此JCE的代码只是Java,但JIT仍然可以加速它。好漂亮,对吧?

要真正测试您的代码,您可能需要使用JIT的预热时间(以启用AES-NI)。您应该能够使用缓冲区,而不是每次为密文生成一个新的数组对象。

更重要的是,可能想要捕获该缓冲区的输出,例如将其异或进入最终缓冲区并将其打印出来。这将使编译器几乎不可能完全跳过代码。如果您对结果本身并不感兴趣,编译器优化很难处理;毕竟,编译器或JIT可以完全跳过加密以获得相同的结果。

您可能还需要在单个循环中执行更多AES操作。您可以实施AES竞赛所需的蒙特卡罗测试作为基础。

© www.soinside.com 2019 - 2024. All rights reserved.