Question

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??

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top