I am working on java application to create a digital signature to sign a document. I already created private key and public key using (Elliptic-curve cryptography) ECC, and now I want to store both keys in mysql database.

I dont have any problem with public key, but my concern is to securely store the private key.

I'm using AES 128 bit to encrypt the private key and 6 digit password from user to store in database. To encrypt it, I need to generate salt and initialize vector as well.

But now, to decrypt it I also need to know same salt and initialization vector (iv) I use to decrypt the encrypted private key.

Question 1:

Is it secure to store salt and vector in database same table with private key? Currently I encode public and private keys, salt and iv and save as string (data type VARCHAR) in database.

Question 2:

Below is current workflow I design. Is this the best practice? I dont want to make too much process that will affect CPU usage.

Creating key

  • Create private key using ECC
  • Encode private key (Bytes To String)
  • Encrypt private key using AES
  • Encode private key, salt, iv (Bytes To String)
  • Store in database as VARHCAR

Signing document

  • Retrieve private key from DB
  • Decode private key, salt, iv
  • Decrypt private key
  • Decode private key
  • Convert decoded key to actual private key for signing

Code snippet to generate key and encryption:

        //Generate salt
        Random r = new SecureRandom();
        byte[] salt = new byte[8];
        //System.out.println("salt: "+salt);

        //initialize vector
        byte[] vector = new byte[128/8];
        IvParameterSpec ivspec = new IvParameterSpec(vector);
        //System.out.println("iv: "+iv);

        //initialize variables
        String MsgToEncrypt = encodedECCprivateKeyBytes;
        String userPin = ParamUtil.getString(actionRequest, "userPin");
        Cipher ecipher;

        //Generating AES key
        SecretKeyFactory factory =  SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec mykeySpec = new PBEKeySpec(userPin.toCharArray(), salt, 10000, 128);
        SecretKey tmp = factory.generateSecret(mykeySpec);
        SecretKeySpec mySecretkey = new SecretKeySpec(tmp.getEncoded(), "AES");

        //==> Create and initiate encryption
        System.out.println("Initiate encryption alogrithm...");
        ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //System.out.println("Algorithm to encrypt private key: " + ecipher);
        ecipher.init(Cipher.ENCRYPT_MODE, mySecretkey, ivspec);
        //System.out.println("SecKey: "+mySecretkey);
  • Why are you encoding the private key both before and after encrypting it? – AndrolGenhald Jan 19 '18 at 17:57
  • AES encryption only accept String (correct me if I am wrong), so I need to encode from Bytes to String first. After encrypted, the data will be Bytes again. So I encode again to get String to store in database as VARCHAR. – Mohamad Raziman Md Dom Jan 20 '18 at 15:05
  • I don't know how Java's implementation works, but generally you would encrypt raw data. What do you mean by "encoding" here? My assumption was base64 for both, but if Java wants a String to encrypt presumably you can convert from byte[] to String without base64 encoding (which causes a size increase). – AndrolGenhald Jan 20 '18 at 19:17
  • Make sense. I dont know why i didnt just convert it from byte[ ] to String, but base64 encoding to get String value. Ty for your feedback – Mohamad Raziman Md Dom Jan 21 '18 at 7:54

I will answer your question in two parts since you asked it in two parts:

Question 1: Is it secure to store salt and vector in database same table with private key? Currently I encode public and private keys, salt and iv and save as string (data type VARCHAR) in database.

Short answer: Yes, it is secure.

Explanation: It is generally accepted that keeping salt in plain-text alongside the hashed password is secure. This is based off of the logic that if an attacker has the salt and the hash, they still need to utilize a brute force attack to attempt to guess the password used to create the hash. Keeping the salt a secret as well would improve security but so long as the password is reasonably strong, not necessary. For the IV, it is much more complicated and in my opinion out of scope to go into here (and out of my comfort zone to explain) but it is considered secure for the IV to be stored in plain-text next to the cipher-text.

Question 2: Below is current workflow I design. Is this the best practice? I don't want to make too much process that will affect CPU usage.

The workflow appears good to me and is about the same as I would have done, with a few details I think you can improve since you are asking for best practice:

  1. First, your salt is a little bit too short. The issue with this is that with an 8 byte salt even when generated using a crypto-random generator (like you are, which is good) there is the chance of collisions where two or more different users are assigned the same salt value. To mitigate this, the recommendation I follow is a salt length of 256 bits or 32 bytes.

  2. Second piece of advice and I am not sure based on your code if you are already aware, but make sure you never re-use the same IV with the same AES key twice. Due to very fancy cryptanalysis this can create vulnerabilities in the encryption making it breakable. Since the key is being generated from a user password which I will assume is rarely changed, make sure you rotate the IV every time you re-encrypt the private key.

  3. It appears you are only doing 10 000 rounds of hashing at the moment. Although this is not horrible, the golden rule I have always followed is 2^(year-2000) iterations. Since it's 2018, 250 000 hashing iterations or as close to this value as you can get before reaching severe performance issues is the best practice.

Otherwise I think everything looks good, you made a good choice in hashing and public-private key algorithms and were wise to seek help to ensure you did not overlook anything.

Hope it helps!

  • 1
    Thank you dFrancisco, very informative reply! If I increase the salt to 32 bytes and do2^(year-2000) iterations, does it will affect system performance? – Mohamad Raziman Md Dom Jan 20 '18 at 15:04
  • Increasing salt size should have no effect, the big jump in hashing iterations will lead to the system slowing down as that is the whole purpose. It takes longer to compute for you, so when an attacker try's to brute force the hash each password guess takes longer to compute as well. – dFrancisco Jan 20 '18 at 16:51
  • In that case, should i use multi threading to generate the keys and decrypting the keys? – Mohamad Raziman Md Dom Jan 22 '18 at 1:09

Yep. It's safe to store the Salt and IV next to the encrypted entry.

To understand why, you need to dig into just what the Salt and IV are intended to do.

Salt is meant as a way of making it so that if one entry is cracked, it won't trickle down to any other entries. If you had a table of encrypted passwords that weren't hashed, as soon as someone cracked one record, they'd also simultaneously crack all the records that shared the same decrypted password. The Salt's not meant to make brute-forcing harder; it's only meant to guarantee each entry is isolated encryption-wise from every other entry. So it doesn't matter if the attacker knows the salt entry for any given record - as long as you use a different salt for each entry, the Salt's doing its job.

Likewise, the IV is meant to stop Known Plaintext Attacks. Its meant to prevent someone from exploiting "These X entries all share similar contents in Bytes X-Y" and using cryptoanalysis to deduce aspects of the Key. The IV basically jumbles the data before its encrypted. So knowing the IV doesn't help the attacker out, either.

So go ahead and store the IV and the Salt alongside the encrypted value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.