Java Cryptography Architecture (JCA) 实践(三)

        本文主要介绍Java加密框架(JCA,Java Cryptography Architecture)实践。Java加密框架主要由java.security和javax.crypto两个包下的API提供服务。

3    加密实践
3.1    消息摘要
使用SHA-256算法计算消息原文plainData的消息摘要。
/**
 * 生成消息摘要
 * 
 * @param plainData
 * @return
 */
public static byte[] generateMessageDigest(byte[] plainData) {
    byte[] digest = null;
    try {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        digest = messageDigest.digest(plainData);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return digest;
}


3.2    MAC
如前所述,MAC需要对称加密密钥,生成方法如下:
/**
 * 生成SecretKeySpec
 * 
 * @return
 */
public static SecretKeySpec generateSecretKeySpec() {
    byte[] keyBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
    String algorithm = "RawBytes";
    SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, algorithm);
    return secretKeySpec;
}

使用HmacSHA256算法计算消息原文plainData的MAC消息摘要
/**
 * 生成MAC摘要
 * 
 * @param plainData
 * @return
 */
public static byte[] generateMacDigest(byte[] plainData) {
    byte[] macBytes = null;
    try {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec key = KeyUtil.generateSecretKeySpec();
        mac.init(key);
        macBytes = mac.doFinal(plainData);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    }
    return macBytes;
}


3.3    数字签名
如前所述,数字签名需要公私密钥对,生成方法如下:
/**
 * 生成KeyPair
 * 
 * @return
 */
public static KeyPair generateKeyPair(String algorithm) {
    KeyPair keyPair = null;
    try {
        if (algorithm == null || algorithm.isEmpty()) {
            algorithm = "DSA";
        }
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        keyPair = keyPairGenerator.generateKeyPair();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return keyPair;
}

使用算法SHA1withRSA和密钥对keyPair计算消息原文plainData的数字签名
/**
 * 生成数字签名(即用私钥加密的消息摘要)
 * 
 * @param plainData
 * @return
 */
public static byte[] generateDigitalSignature(byte[] plainData, KeyPair keyPair) {
    byte[] signatureData = null;
    try {
        Signature signature = Signature.getInstance("SHA1withRSA");
        SecureRandom secureRandom = new SecureRandom();
        signature.initSign(keyPair.getPrivate(), secureRandom);
        signature.update(plainData);
        signatureData = signature.sign();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (SignatureException e) {
        e.printStackTrace();
    }
    return signatureData;
}


3.4    数字签名校验
使用上一节生成的消息原文plainData和密钥对keyPair校验数字签名signatureData
/**
 * 校验数字签名
 * 
 * @param plainData
 * @param signatureData
 * @return
 */
public static boolean verifyDigitalSignature(byte[] plainData, byte[] signatureData, KeyPair keyPair) {
    boolean verified = false;
    try {
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(keyPair.getPublic());
        signature.update(plainData);
        verified = signature.verify(signatureData);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (SignatureException e) {
        e.printStackTrace();
    }
    return verified;
}


3.5    密钥生成与使用
3.5.1    生成与读取keystore文件
(1)使用keytool生成keystore文件
"C:\Program Files\Java\jdk1.6.0_45\bin\keytool" -genkeypair -alias alias -keyalg RSA -keysize 2048 -dname "CN=CN, OU=OU, O=O, L=L, ST=ST, C=CN" -keypass keypass -validity 100 -storetype JKS -keystore keystore.jks -storepass storepass

(2)读取keystore文件
读取keytool生成的keystore文件,导出KeyStore.PrivateKeyEntry类,里面含有公私密钥对和证书。
其中:
keyStoreFileName为keystore.jks
keyStorePassword为storepass
keyStoreAlias为alias
keyPassword为keypass

/**
 * 获取KeyStore中的PrivateKeyEntry
 * 
 * @param keyStoreFileName
 * @param keyStorePassword
 * @param keyStoreAlias
 * @param keyPassword
 * @return
 */
public static KeyStore.PrivateKeyEntry generatePrivateKeyEntry(String keyStoreFileName, String keyStorePassword, String keyStoreAlias, String keyPassword) {
    KeyStore.PrivateKeyEntry privateKeyEntry = null;
    try {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream keyStoreData = new FileInputStream(keyStoreFileName);
        char[] keyStorePasswordChar = keyStorePassword.toCharArray();
        keyStore.load(keyStoreData, keyStorePasswordChar);
        KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(keyPassword.toCharArray());
        KeyStore.Entry keyEntry = keyStore.getEntry(keyStoreAlias, entryPassword);
        privateKeyEntry = (KeyStore.PrivateKeyEntry) keyEntry;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return privateKeyEntry;
}
3.5.2    生成与读取证书
(1)使用keytool生成证书
"C:\Program Files\Java\jdk1.6.0_45\bin\keytool" -exportcert -alias alias -keypass keypass -storetype JKS -keystore keystore.jks -file cert.cert -rfc -storepass storepass
(2)读取证书文件
其中:
    certFileName为cert.cert
/**
 * 生成证书Certificate
 * 
 * @param certFileName
 * @return
 */
public static Certificate generateCertificate(String certFileName) {
    Certificate certificate = null;
    try {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        InputStream certificateInputStream = new FileInputStream(certFileName);
        certificate = certificateFactory.generateCertificate(certificateInputStream);
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    return certificate;
}


3.6    对称加密
(1)生成对称密钥
/**
 * 生成对称密钥SecretKey
 * 
 * @return
 */
public static SecretKey generateRandomSecretKey(SecureRandom secureRandom) {
    SecretKey secretKey = null;
    try {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        if (secureRandom == null) {
            secureRandom = new SecureRandom();
        }
        int keyBitSize = 256;
        keyGenerator.init(keyBitSize, secureRandom);
        secretKey = keyGenerator.generateKey();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return secretKey;
}

扫描二维码关注公众号,回复: 5418615 查看本文章

(2)使用对称密钥加密
其中plainText为消息原文,key为上一步生成的对称密钥,iv为初始化向量
IvParameterSpec iv = new IvParameterSpec(secureRandom.generateSeed(16));

/**
 * 使用对称密钥加密
 * 
 * @return
 */
public static byte[] encryptRandomKey(byte[] plainText, Key key, IvParameterSpec iv) {
    Security.addProvider(new BouncyCastleProvider());
    Cipher cipher = null;
    byte[] cipherText = null;
    try {
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        cipherText = cipher.doFinal(plainText);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return cipherText;
}

(3)使用对称密钥解密
其中cipherText为消息密文,key为第一步生成的对称密钥,iv为初始化向量
IvParameterSpec iv = new IvParameterSpec(secureRandom.generateSeed(16));

/**
 * 使用对称密钥解密
 * 
 * @return
 */
public static byte[] decryptRandomKey(byte[] cipherText, Key key, IvParameterSpec iv) {
    Security.addProvider(new BouncyCastleProvider());
    Cipher cipher = null;
    byte[] plainText = null;
    try {
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        plainText = cipher.doFinal(cipherText);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return plainText;
}
3.7    非对称加密
(1)使用openSSH生成非对称密钥对
1. 生成2048-bit RSA 私钥
$ openssl genrsa -out private_key.pem 2048
2. 将私钥转为PKCS#8 格式(使Java程序能导入)
$ openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der –nocrypt
3. 将公钥导出为DER格式(使Java程序能导入)
$ openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der

这样,在当前目录下产生了公私钥对private_key.der和public_key.der

(2)读取公钥
其中:fileName为第一步生成的public_key.der
/**
 * 读取openSSL生成的RSA公钥(der格式)
 * 
 * @param fileName
 * @return
 */
public static PublicKey readPublicKey(String fileName) {
    PublicKey publicKey = null;
    InputStream inputStream = null;
    try {
        File file = new File(fileName);
        byte[] keyBytes = new byte[(int) file.length()];
        inputStream = new FileInputStream(file);
        inputStream.read(keyBytes);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        publicKey = keyFactory.generatePublic(spec);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return publicKey;
}

(3)使用公钥加密
使用上一步获取的公钥key对消息原文plainText进行加密。
/**
 * 使用密钥加密
 * 
 * @return
 */
public static byte[] encryptFixKey(byte[] plainText, Key key) {
    Security.addProvider(new BouncyCastleProvider());
    Cipher cipher = null;
    byte[] cipherText = null;
    try {
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        cipherText = cipher.doFinal(plainText);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }
    return cipherText;
}

(4)读取私钥
其中,fileName为第一步生成的private_key.der
/**
 * 读取openSSL生成的RSA私钥(PKCS#8格式)
 * 
 * @param fileName
 * @return
 */
public static PrivateKey readPrivateKey(String fileName) {
    PrivateKey privateKey = null;
    InputStream inputStream = null;
    try {
        File file = new File(fileName);
        byte[] keyBytes = new byte[(int) file.length()];
        inputStream = new FileInputStream(file);
        inputStream.read(keyBytes);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        privateKey = keyFactory.generatePrivate(spec);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return privateKey;
}

(5)使用私钥解密
使用上一步获取的私钥key对加密文本cipherText进行解密,可以获取第二步的消息原文。
/**
 * 使用密钥解密
 * 
 * @return
 */
public static byte[] decryptFixKey(byte[] cipherText, Key key) {
    Security.addProvider(new BouncyCastleProvider());
    Cipher cipher = null;
    byte[] plainText = null;
    try {
        cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, key);
        plainText = cipher.doFinal(cipherText);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }
    return plainText;
}
 

猜你喜欢

转载自blog.csdn.net/hualei_c/article/details/87988824
JCA