1

I am trying to simulate asymmetric key system. I use following code to generate key pairs, encrypt, decrypt passwords. I have a distributed environment and for the moment I save the keys generated in a file system. I know that is not secure but its just for testing purposes.

    private static SecureRandom random = new SecureRandom();

    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    protected synchronized void generateKeys() throws InvalidKeyException, IllegalBlockSizeException, 
            BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, 
                NoSuchPaddingException {

        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");

        generator.initialize(256, random);

        KeyPair pair = generator.generateKeyPair();
        Key pubKey = pair.getPublic();
        Key privKey = pair.getPrivate();

        //store public key
        try {
            storeKey(pubKey, Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-publickey")));
        } catch (Exception e) {
            e.printStackTrace();
            DBLogger.logMessage(e.toString(), Status.KEY_GENERATION_ERROR);
        } 

        //store private key
        try {
            storeKey(privKey, Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-privatekey")));
        } catch (Exception e) {
            e.printStackTrace();
            DBLogger.logMessage(e.toString(), Status.KEY_GENERATION_ERROR);
        } 
    }

    protected synchronized String encryptUsingPublicKey(String plainText) throws IllegalBlockSizeException, BadPaddingException, 
        NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, 
            FileNotFoundException, IOException, ClassNotFoundException {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, readKey(Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-publickey"))), random);
        byte[] cipherText = cipher.doFinal(plainText.getBytes());
        System.out.println("cipher: " + new String(cipherText));    

        return new String(cipherText);
    }

    protected synchronized String decryptUsingPrivatekey(String cipherText) throws NoSuchAlgorithmException, 
        NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, FileNotFoundException, 
            IOException, ClassNotFoundException, IllegalBlockSizeException, BadPaddingException {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, readKey(Constants.KEY_PATH.concat(Constants.SERVER_PREFIX.concat("-privatekey"))));
        byte[] plainText = cipher.doFinal(cipherText.getBytes());
        System.out.println("plain : " + new String(plainText));

        return new String(plainText);
    }
    public static void main(String[] args) {
        KeyGenerator keyGenerator = new KeyGenerator();
        try {
            keyGenerator.deleteAllKeys(Constants.KEY_PATH);
            keyGenerator.generateKeys();

            String cipherText = keyGenerator.encryptUsingPrivateKey("dilshan");
            keyGenerator.decryptUsingPublickey(cipherText);

//          String cipherText = keyGenerator.encryptUsingPublicKey("dilshan1");
//          keyGenerator.decryptUsingPrivatekey(cipherText);
        } catch (Exception e) {
            e.printStackTrace();
            DBLogger.logMessage(e.toString(), Status.KEY_GENERATION_ERROR);
        }
    }

This works perfectly well in most of the time. But some times it generates following error. This happens occasionally. Most of the time this works so I have no issue is with the code. I belive this is something to do with the serialization/serialization process to file system. Help is appreciated.

Note : I am using bouncycastle.

Error is as follows,

javax.crypto.BadPaddingException: unknown block type
    at org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(Unknown Source)
    at javax.crypto.Cipher.doFinal(DashoA13*..)
    at com.dilshan.ttp.web.KeyGenerator.decryptUsingPublickey(KeyGenerator.java:105)
    at com.dilshan.ttp.web.KeyGenerator.main(KeyGenerator.java:150)

Happens at,

byte[] plainText = cipher.doFinal(cipherText.getBytes());

in decryptUsingPrivatekey method.

Codo
  • 75,595
  • 17
  • 168
  • 206
Dilshan
  • 3,231
  • 4
  • 39
  • 50
  • 2
    In addition to @Henry's comments the line `plainText.getBytes()` will cause you grief in the future. It uses the default encoding for the platform it is running on. This can vary, and is not what you want. You should always specify an encoding. "UTF-8" will always work, i.e. `plainText.getBytes("UTF-8")`. To go back to a String from bytes use `new String(plaintext, "UTF-8")` – President James K. Polk Jan 01 '13 at 14:21
  • Ok sure I will modify to that. Thanks @GregS – Dilshan Jan 01 '13 at 14:46

1 Answers1

5

The cipher text is binary data. If you convert it to a String using the default encoding it is very likely that you encounter byte sequences that cannot be represented by a character. Thus, during decryption when you convert the String back to a byte array you don't end up with the same bytes and the decryption fails.

To solve that, don't convert the cipher text to a string, instead carry the byte[] around.

Henry
  • 42,982
  • 7
  • 68
  • 84
  • You are correct. The problem is with the method signature. decryptUsingPrivatekey(byte[] cipherText). Instead of making is String I changed it to byte array which worked for me. Thanks. – Dilshan Jan 01 '13 at 11:51