/*
* Copyright (C) 2017 Dominik Schadow, dominikschadow@gmail.com
*
* This file is part of the Java Security project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.dominikschadow.javasecurity.asymmetric;
import com.google.common.io.BaseEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.cert.CertificateException;
/**
* Asymmetric encryption sample with plain Java. Loads the RSA key from the sample keystore, encrypts and decrypts
* sample text with it.
* <p/>
* Uses Google Guava to hex the encrypted message as readable format.
*
* @author Dominik Schadow
*/
public class RSA {
private static final Logger log = LoggerFactory.getLogger(RSA.class);
private static final String ALGORITHM = "RSA";
private static final String KEYSTORE_PATH = "/samples.ks";
/**
* Private constructor.
*/
private RSA() {
}
public static void main(String[] args) {
encrypt();
}
private static void encrypt() {
final String initialText = "RSA encryption sample text";
final char[] keystorePassword = "samples".toCharArray();
final String keyAlias = "asymmetric-sample-rsa";
final char[] keyPassword = "asymmetric-sample-rsa".toCharArray();
try {
KeyStore ks = loadKeystore(keystorePassword);
PrivateKey privateKey = loadPrivateKey(ks, keyAlias, keyPassword);
PublicKey publicKey = loadPublicKey(ks, keyAlias);
byte[] ciphertext = encrypt(publicKey, initialText);
byte[] plaintext = decrypt(privateKey, ciphertext);
printReadableMessages(initialText, ciphertext, plaintext);
} catch (NoSuchPaddingException | NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException |
KeyStoreException | CertificateException | UnrecoverableKeyException | InvalidKeyException |
IOException ex) {
log.error(ex.getMessage(), ex);
}
}
private static KeyStore loadKeystore(char[] keystorePassword) throws KeyStoreException,
CertificateException, NoSuchAlgorithmException, IOException {
try (InputStream keystoreStream = RSA.class.getResourceAsStream(KEYSTORE_PATH)) {
KeyStore ks = KeyStore.getInstance("JCEKS");
ks.load(keystoreStream, keystorePassword);
return ks;
}
}
private static PrivateKey loadPrivateKey(KeyStore ks, String keyAlias, char[] keyPassword) throws KeyStoreException,
UnrecoverableKeyException, NoSuchAlgorithmException {
if (!ks.containsAlias(keyAlias)) {
throw new UnrecoverableKeyException("Private key " + keyAlias + " not found in keystore");
}
return (PrivateKey) ks.getKey(keyAlias, keyPassword);
}
private static PublicKey loadPublicKey(KeyStore ks, String keyAlias) throws KeyStoreException, UnrecoverableKeyException {
if (!ks.containsAlias(keyAlias)) {
throw new UnrecoverableKeyException("Public key " + keyAlias + " not found in keystore");
}
return ks.getCertificate(keyAlias).getPublicKey();
}
private static byte[] encrypt(PublicKey publicKey, String initialText) throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(initialText.getBytes("UTF-8"));
}
private static byte[] decrypt(PrivateKey privateKey, byte[] ciphertext) throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(ciphertext);
}
private static void printReadableMessages(String initialText, byte[] ciphertext, byte[] plaintext) {
log.info("initial text: {}", initialText);
log.info("cipher text: {}", BaseEncoding.base16().encode(ciphertext));
log.info("plain text: {}", new String(plaintext));
}
}