1.1.46. fejezet, Titkosítás, hitelesítés

Aszimmetrukus (RSA) és szimmetrikus (AES) titkosításra és hitelesítésre mintaprogram. A Windows-MY Keystore és JKS kezelésére ajánlom a KeyStore Explorer-t

package hu.infokristaly.homework4signencdec;
 
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
 
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
 
import sun.security.mscapi.SunMSCAPI;
 
public class Homework4SignEncDec {
 
	private static final String fileName = "c:\\temp\\app-icon.png";
 
	private static final String ASSIMETRIC_ALGORITHM = "RSA";
	private static final String ASSIMETRIC_CHIPER_TRANSFORMATION = "RSA/ECB/PKCS1Padding";
	static final int ASSIMETRIC_ALGORITHM_KEYSIZE = 1024;
 
	private static final String SIMETRIC_ALGORITHM = "AES";
	private static final String SIMETRIC_CHIPER_ALGORITHM = "AES/CTR/NoPadding";
	private static final int SIMETRIC_ALGORITHM_KEYSIZE = 256;
 
	static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
	static final String MESSAGE = "Árvíztűrő tükörfúró gép";
	private static final String SIMETRIC_ALGORITHM_PASSWORD = "Secret";
 
	private static final String ALIAS = "pzoli";
 
	private static final String WINDOWSMY_KEYSTORE_PASSWORD = "";
	private static final String WINDOWSMY_CERT_PASSWORD = "";
 
	private static final String JKS_FILE = "c:\\temp\\mykeystore.jks";
	private static final String JKS_KEYSTORE_PASSWORD = "pWd13X";
	private static final String JKS_CERT_PASSWORD = "xTr24P";
 
	private static final String RSA_ENC_SUFFIX = ".rsa.enc";
	private static final String RSA_DEC_SUFFIX = ".rsa.dec";
	private static final String AES_ENC_SUFFIX = ".aes.enc";
	private static final String AES_DEC_SUFFIX = ".aes.dec";
 
	private static KeyStore keyStore;
 
	public static void main(String[] args) throws Exception {
		Security.setProperty("crypto.policy", "unlimited");
		testSign();
		testAES();
		testWindowsMyKeystore();
		testJKSKeyStore();
	}
 
	private static void testSign() throws Exception {
		keyStore = KeyStore.getInstance("Windows-MY", new SunMSCAPI());
		keyStore.load(null, WINDOWSMY_KEYSTORE_PASSWORD.toCharArray());
 
		String signatureText = signDocument(MESSAGE);
		verifySignature(MESSAGE, signatureText);
	}
 
	private static void testAES() throws Exception {
		int maxKeySize = javax.crypto.Cipher.getMaxAllowedKeyLength(SIMETRIC_ALGORITHM);
		System.out.println("Max key size: " + maxKeySize);
 
		IvParameterSpec generatedIv = getIVSecureRandom(SIMETRIC_ALGORITHM);
		SecretKey key = getPasswordBasedKey(SIMETRIC_ALGORITHM, SIMETRIC_ALGORITHM_KEYSIZE, SIMETRIC_ALGORITHM_PASSWORD.toCharArray());
		// Initialization vector to store
		String plainIvBase64 = new String(Base64.getEncoder().encode(generatedIv.getIV()));
 
		byte[] encryptedText = aesEncryptMessage(MESSAGE, generatedIv, key);
 
		// restored Initialization vector
		byte[] restoredIvBytes = Base64.getDecoder().decode(plainIvBase64);
		IvParameterSpec restoredIv = new IvParameterSpec(restoredIvBytes);
		aesDecryptMessage(encryptedText, restoredIv, key);
 
		aesEncryptFile(restoredIv, key);
		aesDecryptFile(encryptedText, restoredIv, key);
	}
 
	private static void testWindowsMyKeystore() throws Exception {
		keyStore = KeyStore.getInstance("Windows-MY", new SunMSCAPI());
		keyStore.load(null, WINDOWSMY_KEYSTORE_PASSWORD.toCharArray());
 
		rsaEncryptFile(fileName, fileName + RSA_ENC_SUFFIX);
		rsaDecryptFile(fileName + RSA_ENC_SUFFIX, fileName + RSA_DEC_SUFFIX, WINDOWSMY_CERT_PASSWORD);
	}
 
	private static void testJKSKeyStore() throws Exception {
		keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
		InputStream in = new FileInputStream(JKS_FILE);
		keyStore.load(in, JKS_KEYSTORE_PASSWORD.toCharArray());
 
		rsaEncryptFile(fileName, fileName + ".jks" + RSA_ENC_SUFFIX);
		rsaDecryptFile(fileName + ".jks" + RSA_ENC_SUFFIX, fileName + ".jks" + RSA_DEC_SUFFIX, JKS_CERT_PASSWORD);
	}
 
	private static byte[] aesEncryptMessage(String message, IvParameterSpec iv, SecretKey key) throws Exception {
		Cipher encCipher = Cipher.getInstance(SIMETRIC_CHIPER_ALGORITHM);
		encCipher.init(Cipher.ENCRYPT_MODE, key, iv);
		byte[] encryptedText = encCipher.doFinal(MESSAGE.getBytes("UTF8"));
		return encryptedText;
	}
 
	private static void aesDecryptMessage(byte[] encryptedText, IvParameterSpec iv, SecretKey key) throws Exception {
		Cipher decCipher = Cipher.getInstance(SIMETRIC_CHIPER_ALGORITHM);
		decCipher.init(Cipher.DECRYPT_MODE, key, iv);
		byte[] decryptedText = decCipher.doFinal(encryptedText);
		String result = new String(decryptedText, Charset.forName("UTF8"));
		System.out.println("[" + result + "]");
	}
 
	private static void aesEncryptFile(IvParameterSpec iv, SecretKey key) throws Exception {
		Cipher encCipher = Cipher.getInstance(SIMETRIC_CHIPER_ALGORITHM);
		encCipher.init(Cipher.ENCRYPT_MODE, key, iv);
 
		byte[] buf = new byte[1024];
		int bufl;
		try (FileOutputStream outputWriter = new FileOutputStream(fileName + AES_ENC_SUFFIX);
				FileInputStream inputReader = new FileInputStream(fileName);) {
			byte[] cipherText = null;
			while ((bufl = inputReader.read(buf)) != -1) {
				cipherText = encCipher.doFinal(copyBytes(buf, bufl));
				outputWriter.write(cipherText);
			}
			outputWriter.flush();
		}
	}
 
	private static void aesDecryptFile(byte[] encryptedText, IvParameterSpec iv, SecretKey key) throws Exception {
		Cipher decCipher = Cipher.getInstance(SIMETRIC_CHIPER_ALGORITHM);
		decCipher.init(Cipher.DECRYPT_MODE, key, iv);
 
		byte[] outBuf = new byte[1024];
		int bufl;
 
		try (FileOutputStream outputWriter = new FileOutputStream(fileName + AES_DEC_SUFFIX);
				FileInputStream inputReader = new FileInputStream(fileName + AES_ENC_SUFFIX);) {
			byte[] plainBytes = null;
			while ((bufl = inputReader.read(outBuf)) != -1) {
				plainBytes = decCipher.doFinal(copyBytes(outBuf, bufl));
				outputWriter.write(plainBytes);
			}
			outputWriter.flush();
		}
	}
 
	private static void rsaEncryptFile(String inFileName, String outFileName) throws Exception {
 
		Certificate cert = keyStore.getCertificate(ALIAS);
		PublicKey pubKey = cert.getPublicKey();
 
		Cipher encryptCipher = Cipher.getInstance(ASSIMETRIC_CHIPER_TRANSFORMATION);
 
		encryptCipher.init(Cipher.ENCRYPT_MODE, pubKey);
 
		byte[] buf = new byte[100];
		int bufl;
		try (FileOutputStream outputWriter = new FileOutputStream(outFileName);
				FileInputStream inputReader = new FileInputStream(inFileName);) {
			byte[] cipherText = null;
			while ((bufl = inputReader.read(buf)) != -1) {
				cipherText = encryptCipher.doFinal(copyBytes(buf, bufl));
				outputWriter.write(cipherText);
			}
			outputWriter.flush();
		}
	}
 
	private static void rsaDecryptFile(String inFileName, String outFileName, String alias_password) throws Exception {
		KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection(alias_password.toCharArray());
		KeyStore.PrivateKeyEntry selectedKey = (KeyStore.PrivateKeyEntry) keyStore.getEntry(ALIAS, keyPassword);
		PrivateKey privKey = selectedKey.getPrivateKey();
 
		Cipher decryptCipher = Cipher.getInstance(ASSIMETRIC_CHIPER_TRANSFORMATION);
		decryptCipher.init(Cipher.DECRYPT_MODE, privKey);
		int outputSize = decryptCipher.getOutputSize(0);
		byte[] buf = new byte[outputSize];
		int bufl;
		try (FileOutputStream outputWriter = new FileOutputStream(outFileName);
				FileInputStream inputReader = new FileInputStream(inFileName);) {
			byte[] decryptedText = null;
			while ((bufl = inputReader.read(buf)) != -1) {
				decryptedText = decryptCipher.doFinal(copyBytes(buf, bufl));
				outputWriter.write(decryptedText);
			}
			outputWriter.flush();
		}
	}
 
	public static boolean verifySignature(String text, String signatureText) throws Exception {
		boolean result = false;
		PublicKey publicKey = (PublicKey) keyStore.getCertificate(ALIAS).getPublicKey();
		try {
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			byte[] signatureBytes = Base64.getDecoder().decode(signatureText);
 
			signature.initVerify(publicKey);
			signature.update(text.getBytes());
 
			result = signature.verify(signatureBytes);
			System.out.println("signature verified: " + result);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return result;
	}
 
	private static String signDocument(final String messageToSign) throws Exception {
		KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection(WINDOWSMY_CERT_PASSWORD.toCharArray());
		KeyStore.PrivateKeyEntry selectedKey = (KeyStore.PrivateKeyEntry) keyStore.getEntry(ALIAS, keyPassword);
		PrivateKey privKey = selectedKey.getPrivateKey();
 
		Signature dmSignature = Signature.getInstance(SIGNATURE_ALGORITHM);
		dmSignature.initSign(privKey);
		dmSignature.update(messageToSign.getBytes());
		String signature = new String(Base64.getEncoder().encode(dmSignature.sign()));
		return signature;
	}
 
	public static KeyPair generateKey() throws NoSuchAlgorithmException {
		KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ASSIMETRIC_ALGORITHM);
		keyGen.initialize(ASSIMETRIC_ALGORITHM_KEYSIZE);
		KeyPair key = keyGen.generateKeyPair();
		return key;
	}
 
	public static byte[] copyBytes(byte[] src, int length) {
		byte[] dest = null;
		if (src.length == length) {
			dest = src;
		} else {
			dest = new byte[length];
			for (int i = 0; i < length; i++) {
				dest[i] = (byte) src[i];
			}
		}
		return dest;
	}
 
	private static SecretKey getPasswordBasedKey(String cipher, int keySize, char[] password) throws Exception {
		byte[] salt = new byte[100];
		SecureRandom random = new SecureRandom();
		random.nextBytes(salt);
		PBEKeySpec pbeKeySpec = new PBEKeySpec(password, salt, 65536, keySize);
		SecretKey pbeKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(pbeKeySpec);
		return new SecretKeySpec(pbeKey.getEncoded(), cipher);
	}
 
	public static IvParameterSpec getIVSecureRandom(String algorithm)
			throws NoSuchAlgorithmException, NoSuchPaddingException {
		SecureRandom random = SecureRandom.getInstanceStrong();
		byte[] iv = new byte[Cipher.getInstance(algorithm).getBlockSize()];
		random.nextBytes(iv);
		return new IvParameterSpec(iv);
	}
 
	public static PublicKey getPublicKeyFromString(String publicKeyText) throws Exception {
		byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyText);
		X509EncodedKeySpec encoded = new X509EncodedKeySpec(publicKeyBytes);
		PublicKey publicKey = KeyFactory.getInstance(ASSIMETRIC_ALGORITHM).generatePublic(encoded);
		return publicKey;
	}
 
	public static String getMD5(String text) {
		byte[] md5 = DigestUtils.getMd5Digest().digest(text.getBytes(Charset.forName("UTF-8")));
		String md5String = new String(Hex.encodeHex(md5));
		return md5String;
	}
 
}

Kapcsolódó hivatkozások