Java tutorial
/** Copyright (c) 2015 Giulliano Bueno Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **/ package com.torresbueno; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FilenameUtils; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.*; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * RSA utility class. * * @author Giulliano Bueno * * RSA - Encrypt data using public key * RSA - Descypt data using private key */ public class RSAEncryptionDecryptionUtil { private String privateKeyFilePath; private String publicKeyFilePath; private PrivateKey privateKey; private PublicKey publicKey; private String privateKeyString; private String publicKeyString; private KeyFactory keyFactoryInstance; public RSAEncryptionDecryptionUtil() { //Security.addProvider(new BouncyCastleProvider()); } private PrivateKey getPrivateKey() throws Exception { if (this.privateKey == null) { if (getPrivateKeyFilePath() != null) { this.privateKey = readPrivateKeyFromFile(getPrivateKeyFilePath()); } else { PrivateKey pk = getPrivateKeyFromString(); if (pk != null) { this.privateKey = pk; } } } return this.privateKey; } /** * Check if the path parameter corresponds to a certificate. * Extensions verified .cer, .csr * @param path * @return true if the path is a certificate. */ private boolean isCertificate(String path) { return "cer".equals(FilenameUtils.getExtension(path)) || "csr".equals(FilenameUtils.getExtension(path)); } private PublicKey getPublicKey() throws Exception { if (this.publicKey == null) { if (getPublicKeyFilePath() != null) { if (isCertificate(getPublicKeyFilePath())) { this.publicKey = readPublicKeyFromCertificate(getPublicKeyFilePath()); } else { this.publicKey = readPublicKeyFromFile(getPublicKeyFilePath()); } } else { PublicKey pbk = getPublicKeyFromString(); if (pbk != null) { this.publicKey = pbk; } } } return this.publicKey; } /** * Sets the private key file path to be used to encrypt and decrypt. * @param publicKeyFilePath */ public void setPublicKeyFilePath(String publicKeyFilePath) { this.publicKeyFilePath = publicKeyFilePath; } /** * @return the public key file path to be used to encrypt and decrypt. */ public String getPublicKeyFilePath() { return publicKeyFilePath; } /** * Sets the private key file path to be used to encrypt and decrypt. * @param privateKeyFilePath */ public void setPrivateKeyFilePath(String privateKeyFilePath) { this.privateKeyFilePath = privateKeyFilePath; } /** * @return the private key file path to be used to encrypt and decrypt. */ public String getPrivateKeyFilePath() { return this.privateKeyFilePath; } /** * Encrypt data using a specific key. * @param data * @param key * @return */ public byte[] encryptData(String data, Key key) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { byte[] dataToEncrypt = data.getBytes(); return encryptBytes(dataToEncrypt, key); } /** * Encrypt data using a specific key. * @param dataToEncrypt * @param key * @return */ public byte[] encryptBytes(byte[] dataToEncrypt, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { byte[] encryptedData = null; Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, key); encryptedData = cipher.doFinal(dataToEncrypt); return encryptedData; } /** * Encrypt data using the public or the private key configured * in the object. * * @param data * @throws IOException */ public byte[] encryptDataWithPrivateKey(String data) throws Exception { return encryptData(data, getPrivateKey()); } public byte[] encryptDataWithPublicKey(String data) throws Exception { return encryptData(data, getPublicKey()); } public byte[] decryptDataWithPublicKey(byte[] data) throws Exception { return decryptData(data, getPublicKey()); } public byte[] decryptDataWithPrivateKey(byte[] data) throws Exception { return decryptData(data, getPrivateKey()); } /** * Decrypt the data using the specified key. * @param data * @param key * @return a byte array with the decrypted data. */ public byte[] decryptData(byte[] data, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { byte[] decryptedData = null; Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, key); decryptedData = cipher.doFinal(data); return decryptedData; } /** * read Public Key From File * @param filePath * @return PublicKey * @throws IOException */ public PublicKey readPublicKeyFromFile(String filePath) throws Exception { // Read file to a byte array. Path path = Paths.get(filePath); byte[] pubKeyByteArray = Files.readAllBytes(path); X509EncodedKeySpec spec = new X509EncodedKeySpec(pubKeyByteArray); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePublic(spec); } /** * Read public key from file. * @param filePath * @return * @throws IOException */ public PrivateKey readPrivateKeyFromFile(String filePath) throws Exception { // Read file to a byte array. String privateKeyFileName = filePath; Path path = Paths.get(privateKeyFileName); byte[] privKeyByteArray = Files.readAllBytes(path); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec); return myPrivKey; } /** * Get a public key from a certificate. * @param certPath * @return * @throws Exception */ public PublicKey readPublicKeyFromCertificate(String certPath) throws Exception { FileInputStream fin = new FileInputStream(certPath); CertificateFactory f = CertificateFactory.getInstance("X.509"); X509Certificate certificate = (X509Certificate) f.generateCertificate(fin); return certificate.getPublicKey(); } /** * Sign a message. * @param data * @param pk * @return */ public byte[] sign(byte[] data, PrivateKey pk) throws Exception { Signature sig = Signature.getInstance("MD5WithRSA"); sig.initSign(pk); sig.update(data); byte[] signatureBytes = sig.sign(); return signatureBytes; } /** * Verify a signature. * @param data * @param signatureBytes * @param publicKey * @return */ public boolean verifySign(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws Exception { try { return verifySignWithMD5withRSA(data, signatureBytes, publicKey); } catch (Exception ex) { return verifySignWithSHA1withRSA(data, signatureBytes, publicKey); } } public boolean verifySignWithSHA1withRSA(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { Signature sig = Signature.getInstance("SHA1withRSA"); sig.initVerify(publicKey); sig.update(data); return sig.verify(signatureBytes); } public boolean verifySignWithMD5withRSA(byte[] data, byte[] signatureBytes, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { Signature sig = Signature.getInstance("MD5WithRSA"); sig.initVerify(publicKey); sig.update(data); return sig.verify(signatureBytes); } /** * Hash a message using MD5. * @param data * @return * @throws Exception */ public byte[] hash(String data) throws Exception { byte[] bytesOfMessage = data.getBytes("UTF-8"); MessageDigest md = MessageDigest.getInstance("MD5"); return md.digest(bytesOfMessage); } public KeyFactory getKeyFactoryInstance() throws NoSuchAlgorithmException { if (keyFactoryInstance == null) { keyFactoryInstance = KeyFactory.getInstance("RSA"); } return keyFactoryInstance; } public void setPublicKeyString(String publicKeyString) { this.publicKeyString = publicKeyString; } public void setPrivateKeyString(String privateKeyString) { this.privateKeyString = privateKeyString; } public String getPrivateKeyString() { return privateKeyString; } public String getPublicKeyString() { return publicKeyString; } /** * Get a private key from the privateKeyString property. * @return a standard private key object. * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public PrivateKey getPrivateKeyFromString() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { if (privateKeyString == null) return null; byte[] encodedPv = Base64.decodeBase64(privateKeyString); PKCS8EncodedKeySpec keySpecPv = new PKCS8EncodedKeySpec(encodedPv); return getKeyFactoryInstance().generatePrivate(keySpecPv); } /** * Get a public key from the publicKeyString property. * @return a standard public key object. * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public PublicKey getPublicKeyFromString() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { if (publicKeyString == null) return null; byte[] encodedPb = Base64.decodeBase64(publicKeyString); X509EncodedKeySpec keySpecPb = new X509EncodedKeySpec(encodedPb); return getKeyFactoryInstance().generatePublic(keySpecPb); } /** * Get a private key object from a string. * @param privateKey - A Base64 encoded string with a PKCS8 encoded key spec. * @return a standard private key object. * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public PrivateKey getPrivateKeyFromString(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { byte[] encodedPv = Base64.decodeBase64(privateKey); PKCS8EncodedKeySpec keySpecPv = new PKCS8EncodedKeySpec(encodedPv); return getKeyFactoryInstance().generatePrivate(keySpecPv); } /** * Get a public key object from a string. * @param publicKey - A Base64 encoded string with a X509 encoded key spec. * @return a standard public key object. * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public PublicKey getPublicKeyFromString(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { byte[] encodedPb = Base64.decodeBase64(publicKey); X509EncodedKeySpec keySpecPb = new X509EncodedKeySpec(encodedPb); return getKeyFactoryInstance().generatePublic(keySpecPb); } }