4

I am writing a server for my android app, they have to communicate encrypted. I have chosen AES encryption for the data, and RSA for the AES Key. Android App uses SpongyCastle, so to have a working server I need a (nearly) equal Provider to use the RSA Public Key of the other communication Partner. I try to use bouncycastle but I cant find a working workaround for this issue.

Server: Eclipse / Client: Android Studio

The Solution described here does NOT work, already tried.

//package and filepath has been shortened

java.lang.SecurityException: JCE cannot authenticate the provider BC
        at javax.crypto.Cipher.getInstance(Cipher.java:657)
        at javax.crypto.Cipher.getInstance(Cipher.java:596)
        at myPackage.Cryption.decrypt(Cryption.java:118)
        at myPackage.Cryption.decryptToObject(Cryption.java:107)
        at myPackage.main.lambda$0(main.java:122)
        at java.lang.Thread.run(Unknown Source)
Caused by: java.util.jar.JarException: file:/C:/[...]/MyJar.jar has unsigned entries - myPackage/Cryption.class
        at javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:500)
        at javax.crypto.JarVerifier.verifyJars(JarVerifier.java:361)
        at javax.crypto.JarVerifier.verify(JarVerifier.java:289)
        at javax.crypto.JceSecurity.verifyProviderJar(JceSecurity.java:159)
        at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:185)
        at javax.crypto.Cipher.getInstance(Cipher.java:653)
        ... 5 more

Followed by a NullPointerException because the decryption has failed.

This is my Cryption class:

import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;

import java.security.*;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

public class Cryption {
    private Key publicKey;
    private PrivateKey privateKey;
    private String AES = "AES";
    private String RSA = "RSA";
    public Cryption() {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        KeyPair keyPair = null;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA, "BC");
            keyPairGenerator.initialize(1024);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception e) {
            e.printStackTrace();
        }
        publicKey = keyPair.getPublic();
        privateKey = keyPair.getPrivate();
    }

    public byte[] getPublicKeyBytes() {
        return publicKey.getEncoded();
    }


    ////////////ENCRYPT


    public EncryptedData encrypt(Object o, byte[] keyRSA) {
        return encrypt(Utils.serialize(o), keyRSA);
    }

    public EncryptedData encrypt(byte[] bytes, byte[] keyRSA) {

        try {
            //get AES Random Key

            KeyGenerator keygen = KeyGenerator.getInstance(AES, "BC");
            keygen.init(128);
            Key aesKey= keygen.generateKey();
            byte[] aesKeyByte = aesKey.getEncoded();

            //AES encryption
            byte[] dataEncyptedAES = null;
            Cipher aescipher = Cipher.getInstance(AES, "BC");
            aescipher.init(Cipher.ENCRYPT_MODE, aesKey);
            dataEncyptedAES = aescipher.doFinal(bytes);

            //encode AES Key
            byte[] encodedAESkey = encodeRSA(aesKeyByte, keyRSA);
            return new EncryptedData(encodedAESkey, dataEncyptedAES);
        }catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] encodeRSA(byte[] data, byte[] keyRSA) {
        try {
            AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(keyRSA);
            AsymmetricBlockCipher e = new RSAEngine();
            e = new org.bouncycastle.crypto.encodings.PKCS1Encoding(e);
            e.init(true, publicKey);

            List<Byte> value = new ArrayList<Byte>();
            int i = 0;
            int len = e.getInputBlockSize();
            while(i<data.length) {
                if(i+len > data.length) len = data.length - i;
                byte[] hexEncodedCipher = e.processBlock(data, i ,len);
                for(Byte b : hexEncodedCipher) {
                    value.add(b);
                }
                i+=e.getInputBlockSize();
            }
            return Utils.convert(value.toArray(new Byte[value.size()]));
        }catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }




    ///////////////////DECRYPT



    public Object decryptToObject(EncryptedData encryptedData) {
        return Utils.deserialize(decrypt(encryptedData));
    }

    private byte[] decrypt(EncryptedData encryptedData) {
        if(encryptedData == null) System.out.println("ENCRYPTED DATA == NULL");
        try {
            //decode AES key
            byte[] decodedAESKey = decryptRSA(encryptedData.getEncryptedAESKey());

            //decrypt data
            byte[] decodedBytes = null;
            Cipher cipherData = Cipher.getInstance(AES, "BC");
            cipherData.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decodedAESKey, 0, decodedAESKey.length, AES));
            decodedBytes = cipherData.doFinal(encryptedData.getDataEncryptedAES());
            return decodedBytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private byte[] decryptRSA(byte[] data) {
        try {
            AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(this.privateKey.getEncoded());
            AsymmetricBlockCipher e = new RSAEngine();
            e = new org.bouncycastle.crypto.encodings.PKCS1Encoding(e);
            e.init(false, privateKey);

            List<Byte> value = new ArrayList<Byte>();
            int i = 0;
            int len = e.getInputBlockSize();
            while(i<data.length) {
                if(i+len > data.length) len = data.length - i;
                byte[] hexEncodedCipher = e.processBlock(data, i ,len);
                for(Byte b : hexEncodedCipher) {
                    value.add(b);
                }
                i+=e.getInputBlockSize();
            }
            return Utils.convert(value.toArray(new Byte[value.size()]));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void clear() {
        privateKey = null;
        publicKey = null;
    }
}

Utils.convert([]) switches between Byte[] and byte[]

I hope this is enough information for you to find a workaround, I failed here.

Have a nice day

Community
  • 1
  • 1
idefixjm
  • 41
  • 1
  • 3
  • 1
    Possible duplicate of [JCE cannot authenticate the provider BC in java swing application](http://stackoverflow.com/questions/13721579/jce-cannot-authenticate-the-provider-bc-in-java-swing-application) – Eli Sadoff Jan 15 '17 at 21:54
  • 1
    Probably you're using the wrong .jar file, you need to use the ...15-on (for *onwards*) .jar file. The signatures for the previous jars are not valid anymore. Please indicate below if this is the case. – Maarten Bodewes Jan 15 '17 at 23:33
  • 1
    Before edit you described the fix in answer #19562164 as 'changing jre/lib/security/java.security and copy used jars in jre/lib/ext'. That's NOT what it says. It says copy **`bc*.jar`** meaning the bcprov-$version.jar **exactly as downloaded** from BouncyCastle. NOT `MyJar.jar` if that is even one bit different from `bc*.jar` from Bouncy. PS: you _don't_ actually need Bouncy; Oracle RSA-PKCS1 is compatible with Bouncy (and Spongy) RSA-PKCS1 because PKCS1 is a standard. OTOH RSA-1024 no longer has much safety margin. – dave_thompson_085 Jan 16 '17 at 01:04
  • 1
    @dave_thompson_085 Right. I never understand why people want to explicitly define the provider of the algorithm in the first place. It could have some value for hardware devices or for edge cases where the implementation is slightly different from one provider to the other, but in general specifying a provider is a bad idea. – Maarten Bodewes Jan 18 '17 at 00:32
  • @dave_thompson_085 thank you, I didn't knew the PS. part, so I just deleted the part with bouncycastle and informed me about RSA PKCS1 without external librarys. – idefixjm Jan 18 '17 at 16:01

0 Answers0