Android 和 Java 密钥生成返回不同的结果

Posted

技术标签:

【中文标题】Android 和 Java 密钥生成返回不同的结果【英文标题】:Android and Java key generation return different results 【发布时间】:2018-04-09 07:41:40 【问题描述】:

我遇到了以下问题。我的应用程序分为两个不同的部分:1)第一部分使用 AES/CBC(Java)加密一些数据,2)第二部分必须检索数据并解密(android)。 要生成密钥,我使用以下代码

SecureRandom saltRand = new SecureRandom(new byte[]  1, 2, 3, 4 );
byte[] salt = new byte[16];
saltRand.nextBytes(salt);

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 1024, 128);
SecretKey key = factory.generateSecret(spec);

SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(key.getEncoded());
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, sr);
sksCrypt = new SecretKeySpec((kg.generateKey()).getEncoded(), "AES");

我的程序不需要不同的“源密钥”(字符串密码),但是只要源密钥相同,它就需要计算相同的密钥。不幸的是,程序的两部分生成的密钥不同,解密阶段失败。 有关如何解决此问题的任何建议?

【问题讨论】:

盐必须相同。 【参考方案1】:

您正在使用随机密钥生成器从给定的输入密钥材料生成密钥。 密钥派生函数是从秘密中派生密钥的函数。有基于密码的密钥派生函数,例如 PBKDF2,它使用密码(加上盐和特定的迭代次数)作为秘密输入。还有一些基于密钥的密钥派生函数,例如 HKDF,它使用密钥和可能的标签或其他输出密钥特定信息作为输入材料。

Java 确实为您提供了一组 PBKDF,PBKDF1 和 PBKDF2,其中 PBKDF2 是您当前使用的较新的。不幸的是,它没有提供开箱即用的 KBKDF。您需要使用(轻量级)Bouncy Castle API 来提供这种功能。我知道是因为我为 Bouncy 提供了各种 KBKDF 的初始实现。

不幸的是,使用SecureRandom 作为替换 KBKDF 不起作用,正如您所发现的那样。 SHA1PRNG算法没有指定好;它是一个依赖于 SHA-1 安全散列函数的函数,仅此而已。因此,实现可以并且确实有所不同,例如在 Android(松散地基于 GNU 类路径)和 Oracle 的 Java 之间。 SHA1PRNG 可能会也可能不会完全依赖种子。在较新的 Android 版本中,它甚至可能被完全不同的东西所取代。

由于您只从输入的密钥材料中派生一个密钥,您不妨直接将key.getEncoded()SecretKeySpec 包装起来,并将其用作密钥。根本不需要执行额外的密钥生成;您已经使用 PBKDF2 派生了一个密钥。额外的包装对密钥材料没有任何作用。 可能只需将算法设置为例如"AES"

【讨论】:

感谢您的回答!既然你知道 Bouncy Castle 包,你能建议我一些链接、文档或任何东西来开始使用它的 API 编程吗?我在互联网上搜索了很多,但我没有找到任何可以清楚地解释它的用法。

以上是关于Android 和 Java 密钥生成返回不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

怎么用android studio生成apk文件

Android 中的 AES 密钥生成

Android Studio创建密钥库错误

php openssl生成的rsa密钥给android和ios使用注意哪些问题

具有 unnest 的 PostgreSQL 查询不返回空值的结果行

使用 MySQL 和 Oracle 进行休眠自动密钥生成