Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encrypt data in Android with a RSA public.pem file generated in Ruby

sorry to ask a particular question, but I need to generate in java code a 'signature' like the following code line in ruby:

signature = OpenSSL::PKey::RSA.new(File.read("PUBLIC_PEM_PATH")).public_encrypt('SECRET_KEY')

I have the .pem key file and the SECRET_KEY that's is something like: F6qxlwQTYWRM3gRfgftryKJHKYZiGXdoy5lDm4

How can I do this ?

Thanks!

UPDATE 1 I tried this :

File pubKeyFile = new File(keyFileName);
    DataInputStream inputStream;
    byte[] signature = null;
    try {
        inputStream = new DataInputStream(new FileInputStream(pubKeyFile));
        byte[] pubKeyBytes = new byte[(int)pubKeyFile.length()];
        inputStream.readFully(pubKeyBytes);
        inputStream.close();

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubKeyBytes);
        RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        signature = cipher.doFinal(secretKey.getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return signature;

And got this error:

java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag

UPDATE2 I managed to load a public key from a .pem file. But now, Im getting an error from the cipher.

public static byte[] getSignature(String keyFileName, byte[] secretKey){
    byte[] signature = null;
    try {
        PublicKey pubKey = readKeyFromFile(keyFileName);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        signature = cipher.doFinal(secretKey);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return signature;
}
private static PublicKey readKeyFromFile(String keyFileName) throws IOException {
    InputStream in = new FileInputStream(keyFileName);
    DataInputStream din = new DataInputStream(in);
    try {
        BigInteger m = BigInteger.valueOf(din.readLong());
        BigInteger e = BigInteger.valueOf(din.readLong());
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        RSAPublicKey pubKey = (RSAPublicKey) fact.generatePublic(keySpec);
        return pubKey;
    } catch (Exception e) {
        throw new RuntimeException("Spurious serialisation error", e);
    } finally {
        din.close();
    }
}

The error log:

javax.crypto.IllegalBlockSizeException: input must be under 8 bytes

Any thoughts??

like image 360
dum4ll3 Avatar asked Feb 21 '14 21:02

dum4ll3


People also ask

How does RSA encrypt a string?

RSA(Rivest-Shamir-Adleman) is an Asymmetric encryption technique that uses two different keys as public and private keys to perform the encryption and decryption. With RSA, you can encrypt sensitive information with a public key and a matching private key is used to decrypt the encrypted message.

How do I decrypt RSA?

To decrypt a ciphertext C using an RSA public key we simply compute the plaintext M as: M = Cd mod N. Note that both RSA encryption and RSA decryption involve a modular exponentiation and so we would be well advised to use the Repeated Squares Algorithm if we want to make these processes reasonably efficient.

How do you decrypt asymmetric encryption?

Asymmetric encryption uses a mathematically related pair of keys for encryption and decryption: a public key and a private key. If the public key is used for encryption, then the related private key is used for decryption. If the private key is used for encryption, then the related public key is used for decryption.


2 Answers

So finally, after hours of research I came with a solution and finally could get read my public key from .pem file and generate an instance of this key. Hence, I managed to encrypt the data.

But I had to copy and paste the key content without any special character like '\n' and make a publicKeyString with it

----------BEGIN RSA PUBLIC KEY---------

key content

----------END RSA PUBLIC KEY---------

static public PublicKey publicKey(String publicKeyString) {
    try {
        byte[] decodedPublicKey = Base64.decode(publicKeyString, 0);
        ASN1InputStream in = new ASN1InputStream(decodedPublicKey);
        ASN1Primitive obj = in.readObject();
        RSAPublicKeyStructure keyStruct = RSAPublicKeyStructure.getInstance(obj);
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(keyStruct.getModulus(), keyStruct.getPublicExponent());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

I failed even when I tried to use PEMReader from bouncy castle. All the problems have something to do with keys generated in Ruby version prior 1.9.3 as described with details here.

Anyway, thanks a lot for the attention disposed.

like image 181
dum4ll3 Avatar answered Oct 06 '22 22:10

dum4ll3


Looks like key wrapping (encryption) to me. Use bouncy castle to read the PEM file, then use Cipher.getInstance("RSA/ECB/PKCS1Padding") to encrypt the secret key, and base 64 encode the result... You could also try the mode Cipher.WRAP_MODE to see if that works. Note that encryption will always return a different result, the only way to test for compatibility is to decrypt it with the other software.

like image 38
Maarten Bodewes Avatar answered Oct 06 '22 23:10

Maarten Bodewes