开发者

Securing a private key on disk using symmetric encryption in Java

开发者 https://www.devze.com 2023-02-11 04:53 出处:网络
I have a distributed application which polls for commands from a central server and the content of those commands are \"signed\" by a private key with the public key deployed along with the applicatio

I have a distributed application which polls for commands from a central server and the content of those commands are "signed" by a private key with the public key deployed along with the application at each remote site. Each command is signed with the private key and that signature is verified before the command is executed.

Here is how I generate my public/private key pairs in java. (I realize, we should be doing more then 1024)

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
KeyPair pair = keyGen.generateKeyPair();

The new requirement is that in addition to sending simple relatively safe commands, we now want to send commands which will instruct our software to download and execute an installer to update itself. This has the potential to open up a big hole if not done correctly. The "execute update installer" command will be signed as always and will also include the md5 of executable which will be downloaded and run. So, the signature on the command must be correct (and will include the md5) and then calculated md5 on the downloaded file will need to be correct, before the execution will occur. This should take care of most attack vectors I can think of. Any others I should be concerned about?

So, now I am directing my attention to securing the private key on the server where these commands originate. If that private key is obtained, it is game over. How should I secure that key on disk?

My thought is to use symmetric encryption with a passphrase to secure that private key.

My current solution is as follows:

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();

(exceptions removed for clarity)

This basically randomly generates a salt, uses passphrase to come up with key and then stores the resulting salt, IV and cipher text in a file ready for decryption.

However, I feel something is missing here. Like I should also somehow include some type of MAC on the key so that I know I get a valid description? Maybe it is a simple as just putting 5 or 6 bytes of known text before the private key? A bad passphrase right now just results in bad padding exception, but I read that this might not always be the case and some bad passphrases will decode and result in junk. I feel I need to guard against this.

Can someone let me know if I am on the right track 开发者_高级运维here and provide some feedback. It is important that I get this as secure as possible..


Including a hash or an HMAC is reasonable, given you want to know if you mistyped your passphrase. Otherwise, your solution looks reasonable to me.

One other thing you can do to store it as securely as possible: take it offline. Put copies on a couple of USB keys, store one somewhere safe but to hand, and the backup in a safety deposit box or with a lawyer. It's very heard to get the secret key if it's physically inaccessible.


Not using a HMAC or a well known prefix might be used in some situations to make it harder for the attacker to crack. Note that if you do not include a HMAC you still get decoding exceptions in some situations (caused by a broken padding) which will be enough to recognize a wrong password.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号