Java rsa key generate rsa

RSA Signing and Encryption in Java

How to create a RSA keypair and use it to sign, verify and encrypt information in Java

When it comes to encryption and signing RSA is the de facto standard for public key cryptography. Invented in 1977 RSA (named after it’s inventors, Ron Rivest, Adi Shamir, and Leonard Adleman) and it’s successors are still used in many if not most of the systems you use today. It is in fact one of the core components of what keeps your passwords safe when logging in; HTTPS. In this post I will show you how to use RSA in Java.

Introduction

As said RSA is a public key cryptography ‘asymmetric’ algorithm. This differs from the ‘shared secret’ ‘symmetric’ algorithms like DES or AES in that there are two keys. A public key that you share with anyone and a private key you keep secret. The public key can be used to encrypt data which can then only be decrypted using the private key. The private key can also be used to sign data; this signature can then be sent together with the data and used with the public key to verify that the data is not tampered with.

Читайте также:  Html5 link rel html

When you connect to a server over HTTPS the security layer (SSL) uses this mechanism to secure your connection. It however does not use RSA to encrypt your data directly; RSA is a rather slow algorithm. Instead RSA is used to exchange a symmetric key (for example AES) which is then used to encrypt data.

The complete code example can be found in this Gist.

Generating key pairs in Java

So before we can actually do any form of encryption we need to have a public/private key pair; fortunately Java makes it quite easy to generate these for us! Let’s look at some code:

public static KeyPair generateKeyPair() throws Exception

We get a RSA KeyPairGenerator instance and initialize it with a bit size of 2048 bits and pass in a new SecureRandom(). The latter is used as the entropy or random data source for the generator. On the third line we request it to generate a key pair. That’s all there is to generating a key pair.

If you want to use a key pair stored in a key store instead: I will explain this a bit further down. Let’s first try to encrypt and decrypt some information.

Encryption / Decryption

So now that we have a public/private pair, let’s use it to first encrypt a message and then decrypt the cipher text. Let’s start with the encrypt method:

public static String encrypt(String plainText, PublicKey publicKey) throws Exception

In the example we get an instance of the RSA cipher and set it up in encrypt mode where we also pass in the public key used to encrypt the message. We pass in the bytes of the plainText string in one go and end up with a byte array of encrypted bytes. These bytes then get base 64 encoded and returned.

Now we’ll also need a decrypt method:

public static String decrypt(String cipherText, PrivateKey privateKey) throws Exception

So the code above looks very similar. We get a RSA cipher, initialize it with the private key this time, and decrypt the bytes and turn them into a String again. So let’s put it all together:

//First generate a public/private key pair KeyPair pair = generateKeyPair(); //Our secret message String message = "the answer to life the universe and everything"; //Encrypt the message String cipherText = encrypt(message, pair.getPublic()); //Now decrypt it String decipheredMessage = decrypt(cipherText, pair.getPrivate()); System.out.println(decipheredMessage);

This will, after a short wait, print «the answer to life the universe and everything» in your console. You should also notice that it takes quite a bit of time. As explained RSA is rather slow; much slower than symmetric algorithms like AES.

Sign / Verify

So with a public key we can encrypt messages which then can be decrypted with the private key. While theoretically possible to do the reverse (encrypt with private key, decrypt with public) this is not secure at all and most libraries (including java.security) won’t let you.

What we can do however, and this is very useful when building API’s, is sign a message with our private key and verify the signature with the public key. This allows us to make sure that a message indeed comes from the creator of our public key (the private key holder) and that it wasn’t tampered with in transit. So let’s start with the sign function:

public static String sign(String plainText, PrivateKey privateKey) throws Exception

It looks quite similar to our encrypt/decrypt functions. We get a Signature of type SHA256withRSA, initialize it with the private key, updated it with all the bytes in our message (you can do this in chunks with for example large files) and then generate a signature with the .sign() method. This signature is then returned as a Base64 encoded string.

You might wonder what that SHA256 bit is doing there. As shown before RSA is a rather slow algorithm. So SHA256withRSA doesn’t actually calculate a signature over all the input (which can be gigabytes worth of data), it actually calculates a SHA 256 over the entire input, pads it, and then calculates a signature. If you’re interested the entire process is described in this RFC.

So now that we have a signature we can use it to verify the message:

public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception

Again quite similar to the previous bit. We get a Signature instance, set it up to verify with the public key, feed it all the plain text bytes and then use the signature bytes to see if the signature matches. This verify method returns a boolean indicating whether the signature is valid or not.

So to put this all together:

KeyPair pair = generateKeyPair(); String signature = sign("foobar", pair.getPrivate()); //Let's check the signature boolean isCorrect = verify("foobar", signature, pair.getPublic()); System.out.println("Signature correct: " + isCorrect);

This should output «Signature correct: true». Go ahead and try to change a single byte of the input message or message to verify; it will fail to verify (return false instead).

Java KeyStore

If you ever are going to use this in a production scenario you are probably going to not generate keypairs on the fly (while that certainly has it’s uses!) but instead use Java KeyStores. KeyStores are a storage mechanism where you can have a number of keys stored in a single file. This file is encrypted itself (with PBEWithMD5AndTripleDES, quite a mouthful!) and has both per-store and per-key passwords.

So first let’s generate a keystore using the keytool JDK utility:

keytool -genkeypair -alias mykey -storepass s3cr3t -keypass s3cr3t -keyalg RSA -keystore keystore.jks

This will create a keystore.jks file containing a single public / private key pair stored under the alias ‘mykey’. Both the store and the key are password protected with the password ‘s3cr3t’. Keytool will ask you a bunch of questions (like firstname, lastname, etc.) which you can leave empty if you want. The last question, if the information is correct, will default to ‘no’ so don’t just blindly enter through all of them 😉

We should now have a keystore.jks file, I suggest putting it in your src/java/resources folder or in any other folder where it ends up on your classpath. So let’s see how we can read our keys from the store:

public static KeyPair getKeyPairFromKeyStore() throws Exception < InputStream ins = RsaExample.class.getResourceAsStream("/keystore.jks"); KeyStore keyStore = KeyStore.getInstance("JCEKS"); keyStore.load(ins, "s3cr3t".toCharArray()); //Keystore password KeyStore.PasswordProtection keyPassword = //Key password new KeyStore.PasswordProtection("s3cr3t".toCharArray()); KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("mykey", keyPassword); java.security.cert.Certificate cert = keyStore.getCertificate("mykey"); PublicKey publicKey = cert.getPublicKey(); PrivateKey privateKey = privateKeyEntry.getPrivateKey(); return new KeyPair(publicKey, privateKey); >

In the example we open the key store on the classpath via getResourceAsStream. If you want you can adapt this to reading from a FileInputStream if your key store is not on the classpath.

We need to specify the same password twice; once for the store and once for the key itself. In production environments these are often different keys and not hard-coded so keep that in mind! We get the «mykey» private key and certificate (public key) entries which we can then use to create a KeyPair. We can use this key pair in exactly the same way in the code we created before:

KeyPair pair = getKeyPairFromKeyStore(); String signature = sign("foobar", pair.getPrivate()); //Let's check the signature boolean isCorrect = verify("foobar", signature, pair.getPublic()); System.out.println("Signature correct: " + isCorrect);

Conclusion

I hope this is a nice starting point to help you integrate RSA or similar asymmetric algorithms in your code. I myself had to piece most of this information together from different sources recently when I had to sign REST requests to a partner API with a private key of which they have the public counterpart. This allows them to verify that my side is actually the party creating the requests and that the content of the requests weren’t tampered with.

Further reading

Источник

How to generate RSA keys with Java

In Java, we can use native libraries to create RSA public and private keys. We will create, store, and load public and private keys in this example.

How to create public and private RSA Keys with Java

The algorithm RSA consists of three steps: key generation, encryption and decryption

  1. Use KeyPairGenerator to generate a pair of keys.
  2. Get the keys and save
  3. Load keys and use to encrypt and decrypt

Create Key Pair. Private and Public

Returns a KeyPairGenerator object that generates public/private key pairs for the specified algorithm RSA. Initializes the key pair generator for a certain keysize. In this case the generated key will have a size of 2048 bits.

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(2048); 

Once you have initialized, you can create a key pair.

KeyPair kp = kpg.generateKeyPair(); PrivateKey aPrivate = kp.getPrivate(); PublicKey aPublic = kp.getPublic(); 

Save Private and Public

try (FileOutputStream outPrivate = new FileOutputStream("key.priv"))  outPrivate.write(aPrivate.getEncoded()); > try (FileOutputStream outPublic = new FileOutputStream("key.pub"))  outPublic.write(aPublic.getEncoded()); > 

Information about the keys. In the output of the console you can see that the keys are created in these codifications.

System.out.println("Private key: " + aPrivate.getFormat()); System.out.println("Public key: " + aPublic.getFormat()); // output.. // Private key: PKCS#8 // Public key: X.509 

Load Private and Public keys

To read the key files, you need the bytes of the file. From there you must use PKCS8EncodedKeySpec to read the private key and X509EncodedKeySpec for the public key. Note that PKCS8EncodedKeySpec and X509EncodedKeySpec corresponds to the encoding you obtained previously.

Load Private Key in PrivateKey using KeyFactory

File privateKeyFile = new File("key.priv"); byte[] privateKeyBytes = Files.readAllBytes(privateKeyFile.toPath()); KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA"); EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); PrivateKey privateKey = privateKeyFactory.generatePrivate(privateKeySpec); 

Load Public Key in PublicKey using KeyFactory

File publicKeyFile = new File("key.pub"); byte[] publicKeyBytes = Files.readAllBytes(publicKeyFile.toPath()); KeyFactory publicKeyFactory = KeyFactory.getInstance("RSA"); EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); PublicKey publicKey = publicKeyFactory.generatePublic(publicKeySpec); 

Running this code

Both files are created at the root of the project. Then, you can move them where you need to use them.

Key-pair-files

Conclusion

In this post, you learned how to create RSA keys using Java standard libraries.

If you want to learn how to encrypt and decrypt using those keys visit this article.

See also

Источник

Оцените статью