我有一个分布式应用程序,它从中央服务器轮询命令,这些命令的内容由私钥“签名”,公钥与每个远程站点的应用程序一起部署。每个命令都使用私钥签名,并且在执行命令之前验证该签名。
这是我在 java 中生成公钥/私钥对的方法。(我意识到,我们应该做的不仅仅是 1024)
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
KeyPair pair = keyGen.generateKeyPair();
新的要求是,除了发送简单的相对安全的命令外,我们现在还想发送命令来指示我们的软件下载并执行安装程序以自我更新。如果没有正确完成,这有可能会打开一个大洞。“执行更新安装程序”命令将像往常一样被签名,并且还将包括将下载并运行的可执行文件的 md5。因此,命令上的签名必须正确(并且将包括 md5),然后在下载文件上计算出的 md5 需要正确,然后才会执行。这应该可以解决我能想到的大多数攻击向量。还有其他我应该关心的吗?
因此,现在我将注意力集中在保护这些命令源自的服务器上的私钥上。如果获得了该私钥,则游戏结束。我应该如何保护磁盘上的密钥?
我的想法是使用带有密码的对称加密来保护该私钥。
我目前的解决方案如下:
char[] passphrase; // Actual passphrase
PrivateKey privateKeyObj; // Actual Private Key
byte[] privateKeyBytes = privateKeyObj.getEncoded();
byte[] salt = new byte[8];
new SecureRandom().nextBytes(salt);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passphrase, salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(privateKeyBytes);
FileOutputStream outputFileStream = new FileOutputStream(outputFile);
outputFileStream.write(salt);
outputFileStream.write(iv);
outputFileStream.write(ciphertext);
outputFileStream.close();
(为清楚起见,删除了例外)
这基本上是随机生成一个盐,使用密码来提供密钥,然后将生成的盐、IV 和密文存储在一个文件中以供解密。
但是,我觉得这里缺少一些东西。就像我还应该以某种方式在密钥上包含某种类型的 MAC,以便我知道我得到了有效的描述?也许只是将 5 或 6 个字节的已知文本放在私钥之前很简单?现在一个错误的密码短语只会导致错误的填充异常,但我读到这可能并非总是如此,一些错误的密码短语会解码并导致垃圾邮件。我觉得我需要警惕这一点。
有人可以让我知道我是否在正确的轨道上并提供一些反馈。重要的是我要尽可能安全..