AES 加密交叉组件 Java/Scala 和 C

AES encryption cross-component Java/Scala and C

我正在尝试在不同系统之间进行跨组件加密。目前,我无法真正匹配输出。 我正在为 C 使用 openssl/aes/h 库,为 Java/Scala 使用 javax.crypto。 我在更改 C 系统中的代码方面没有太大的灵活性,因此我需要修改 Java/Scala 代码。

#include <string.h> 
#include <openssl/aes.h>

char key[] = "aaaaaaaaaaaaaaaa";

int main(){
 unsigned char text[]="hello";
 unsigned char enc_out[80];
 unsigned char dec_out[80];

 AES_KEY enc_key, dec_key;

 AES_set_encrypt_key(key, 128, &enc_key);
 AES_encrypt(text, enc_out, &enc_key);
 return 0
}

C 代码大致类似于 that.Using AES_set_encrypt_key 和 AES_encrypt 调用,除了在需要时用 0 填充(当密钥不是 128 位时)。对于这个简单的例子,填充应该无关紧要。

在我的 Scala 代码中:

  def aes_encrypt(value: String, k: String): Array[Byte] = {
    val cipher = Cipher.getInstance("AES")
    val key = Arrays.copyOf(k.getBytes("UTF-8"), 16)
    val secretKey: SecretKeySpec = new SecretKeySpec(key, 0, key.length, "AES")
    cipher.init(Cipher.ENCRYPT_MODE, secretKey)
    cipher.doFinal(value.getBytes("UTF-8"), 0, value.getBytes("UTF-8").length)
  }

使用密钥 "aaaaaaaaaaaaaaaa" 和消息 "hello" ,在 base64 中

C代码给出"XaiMOCo7KteRUkejpd8JLA=="

在Scala/Java“7GHRfFgKVdaAiwti36tqDQ==”

我正在尝试匹配输出,但我无法做到。 我为 Scala 代码尝试了不同的算法,但我不确定如何匹配 C 输出。

我试图查看 AES_set_encrypt_key 和 AES_encrypt 调用的文档,但我无法从中挖掘出太多信息。我知道 openssl 库中有更好的用户友好调用,例如 evp_encryption 调用,但我无法摆脱 AES_set_encrypt_key 和 AES_encrypt

I am trying to match the outputs, but I have not been able to do it...

对于 OpenSSL,您在 ECB 模式下操作密码,您负责填充。我相信 OpenSSL 正在加密由 6 个字符(hello[=13=])和 10 个垃圾字符组成的 16 个字节。

对于Java,我相信你使用的是AES/ECB/PKCS5Padding的密码。 value: String 使用 PKCS 填充无条件填充。填充还意味着 16 字节的明文将扩展为 32 字节的密文,而 OpenSSL 仍为 16。

在这种情况下,最好返回测试向量以查看哪个实现有分歧。对于 AES,您经常使用 Brian Gladman 的向量。


I have tried to look into the documentation of AES_set_encrypt_key and AES_encrypt calls, but I couldn't dig too much out of it. I know that there are better user friendly calls from the openssl library like evp_encryption calls, but I can't get away from AES_set_encrypt_key and AES_encrypt

OpenSSL 不记录它们,因为它们不想让您使用它们。如果您与 AES_encrypt 和朋友待在一起,那么您就嫁给了纯软件实现。您有时还会遇到字节顺序问题,因为 EVP 接口会为您处理这些问题。最后,您将不会享受硬件加速,例如 i686 上的 AES-NI 或 ARMv8 上的 AES。


The C code gives XaiMOCo7KteRUkejpd8JLA==, in Scala/Java 7GHRfFgKVdaAiwti36tqDQ==

相关,Scala/Java 是正确的 如果 您的目标是使用 PKCS 填充的 ECB 模式。我可以用 Crypto++ 复制 Scala/Java 结果(它的 StreamTransformationFilter 默认使用 PKCS 填充):

int main(int argc, char* argv[])
{
  byte key[] = "aaaaaaaaaaaaaaaa";
  ECB_Mode<AES>::Encryption enc(key, 16);
  string result;

  StringSource ss(string("hello"), true,
                  new StreamTransformationFilter(enc,
                       new Base64Encoder(
                           new StringSink(result))));

  cout << result << endl;

  return 0;
}

来自评论

I will try to do AES/ECB/NoPadding and the do the padding myself in Scala.

您仍然需要避免 C 程序中的垃圾字符。也许类似下面的内容可以帮助您匹配 Java 的 PKCS #7 padding0x0b 应用了 11 次):

unsigned char text[] = "hello\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";

这是一个用 PKCS #7 padding 填充的较大字符串(0x06 应用了 6 次):

unsigned char text[] = "hellohello\x06\x06\x06\x06\x06\x06";

如果字符串长度为16,则应用0x10 16次。


When using ECB, does it require an IV vector?

没有。 ECB 模式不需要 IV。它在一个密钥下加密一个 16 字节的块(仅此而已)。