在Java中使用AES 256加密RSA私钥

Nob*_*ody 6 java encryption rsa aes private-key

我正在用Java编写安全的文件共享应用程序.一般架构如下所示:

  1. 用户希望加密文件以在多个用户之间进行安全共享.
  2. 应用程序在客户端上生成随机UUID,并将其用作AES 256密码,并使用UUID加密数据.
  3. 然后使用每个人的公钥对UUID进行RSA加密.每个共享用户一次.
  4. 每个加密的UUID数据包都作为文件的一部分存储在自定义文件头中.
  5. 然后将该文件上载到其他人可以访问的服务器.
  6. 用户可以各自使用其私钥来读取AES加密密钥并解密文件.

这是捕获.用户的私钥必须加密并存储在我们数据库的服务器上,以便可以从多个位置访问这些文件.在上传到服务器之前,私钥将在客户端上使用用户选择的密码进行加密.

我想使用AES 256位加密来做到这一点.而且我想在不依赖BouncyCastle库或任何第三方库的情况下完成整个过程.它需要使用标准的Java 5库,这就是我选择使用AES 256加密和RSA而不是像PGP这样的原因.

任何人都可以找到任何本质上不安全的方法,或者想一个更有效的方法来做到这一点?

编辑:

好的,我正在更新问题,因为我得到的所有答案都表明我没有将私钥传输到服务器.我需要服务器上的私钥的原因是因为用户需要能够从多个客户端和多个位置(即:他们的iphone,他们的ipad,他们的工作笔记本电脑,他们的家用电脑)访问他们的数据.他们不希望必须在设备之间管理和复制他们的密钥,这比将密钥存储在我们的服务器上更加不安全,因为他们最终会在那时通过电子邮件将它们发送给自己.

Jer*_*fin 5

这个问题的主要问题是使用UUID.虽然UUID(有点)保证是唯一的,但它们所包含的相当多的东西是可以预测的; 在一台机器上生成的所有UUID中,大量数量保持不变.因此,如果一个人可以访问(例如)他们自己的密钥,他们可能很容易猜到很多其他人的密钥.

另一个有问题的部分是将用户的私钥存储在服务器上.这使得整个方案的其余部分相对脆弱,因为访问这些密钥显然可以访问所有其余数据.它(显然)意味着您通常会解密服务器上的数据,因此当用户通过网络访问该数据时,它需要重新加密以进行传输,并在用户的计算机上解密,或者否则你将以明文传输数据(从而使大多数加密无效).

编辑:关于我怎么想我会这样做:

我有一个列表的公共服务器上的按键.当客户端想要与其他客户端共享文件时,它从服务器获取这些客户端的公钥.然后它生成一个安全的随机密钥,并使用该密钥加密数据.然后,它使用应该能够访问数据的所有其他客户端的公钥来加密随机密钥.将它们放在一起,然后将它们传输到服务器.然后,其他客户端可以下载流,使用其私钥解密密钥,并使用它来解密数据本身.

这意味着每个客户的私钥仍然是真正的私密 - 它永远不必以任何形式离开他们的机器.他们所有人必须与世界其他地方共享的是他们的公钥(根据定义,它不应该导致安全问题).

有了这个,两个明显的攻击线是针对随机数生成器,而不是针对RSA本身.对于随机数生成器,我使用Java的SecureRandom - 这正是它的目的,如果内存服务它已经过仔细检查,并且对它的重大突破似乎不太可能.

我不会试图评论RSA本身的安全性.目前,我认为您首要关注的是协议,而不是加密算法.可以说,如果RSA被严重破坏,你显然需要更改你的代码,但你有很多公司.

有了这个,客户端可以安全地存储他们的私钥.我喜欢那份工作的智能卡,但有很多选择.从服务器和协议的角度来看,它已经不再是一个真正的因素了.

编辑2:至于处理多个设备,我想我只是将每个设备视为一个单独的用户,拥有自己的公钥/私钥对.然后我(可能)将这些组合在一起由实际用户组成,所以我可以轻松地选择"Joe Blow"来让他访问他的所有设备 - 但是通过分层显示,我也可以很容易地限制对子集的访问其中,如果我想在他的办公室机器上与乔分享它,但它足够灵敏,我不希望它在看到它的时候看到他的肩膀,我也很容易做到这一点.

这使用户的生活变得简单,但保留了相同的基本安全模型(即,私钥保持私有).

  • @Unsavory:不,UUID(至少通常)甚至不接近加密随机.就私钥而言,它非常简单:几乎所有安全方案中最大的弱点是用户的密码,通常很容易猜到.如果我能得到一个加密密码的完整文件,我很可能猜到至少1/4的密码.在任何情况下都是如此,但是获取文件使字典攻击相对容易.Salt有帮助,但不能将所有加密密码放在一个地方有助于更多. (2认同)

eri*_*son 2

您概述的方案相当于 CMS(S/MIME 底层标准)和 PGP;从根本上来说,它是安全的。在CMS中,这种模式称为“密钥传输”。您还可以使用多方“密钥协议”以及 DH 或 ECDH 等算法。

唯一的问题是您使用的 AES 密钥选择不当。

我想不出任何理由使用包含非随机位的随机 UUID。只需使用 Java 加密体系结构的正常密钥生成机制即可。密钥、明文和密文都应表示为字节序列,除非您需要容纳某些仅容纳文本的外部存储或传输。

Iterable<Certificate> recipients = null;
KeyGenerator gen = KeyGenerator.getInstance("AES");
gen.init(256);
SecretKey contentEncryptionKey = gen.generateKey();
Run Code Online (Sandbox Code Playgroud)

初始化 AES 密码并让提供商选择 IV。

Cipher contentCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
contentCipher.init(Cipher.ENCRYPT_MODE, contentEncryptionKey);
AlgorithmParameters params = contentCipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
Run Code Online (Sandbox Code Playgroud)

对于每个收件人,初始化 RSA 密码并加密 AES 密钥。

Cipher keyEncryptionCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
for (Certificate recipient : recipients) {
  keyEncryptionCipher.init(Cipher.WRAP_MODE, recipient);
  byte[] encryptedKey = keyEncryptionCipher.wrap(contentEncryptionKey);
  /* Store the encryptedKey with an identifier for the recipient... */
}
/* Store the IV... */ 
/* Encrypt the file... */
Run Code Online (Sandbox Code Playgroud)

让用户选择并记住具有 256 位有效强度的密码是不合理的。为了获得这种强度,您必须随机选择密码,将其编码为文本,然后让用户将其写在卡片上。如果您确实需要那么大的强度,您可以查看基于智能卡的解决方案来存储用户的 RSA 密钥。

我强烈建议使用 CMS 库来存储您的文件。它将增加您使用的协议安全、您使用的代码经过更多审查以及其他工具、库和系统可以与加密消息进行互操作的机会。BouncyCastle 的 API 有点晦涩,但可能值得学习。

(我不记得 Java 5 是否支持“RSA/ECB/OAEPWithSHA-512AndMGF1Padding”;如果支持,您应该使用它而不是 PKCS1Padding。)