Java實現7種常見密碼算法

原創:扣釘日記(微信公眾號ID:codelogs),歡迎分享,轉載請保留出處 。
簡介前面在密碼學入門一文中講解了各種常見的密碼學概念、算法與運用場景,但沒有介紹過代碼,因此,為作補充 , 這一篇將會介紹使用Java語言如何實現使用這些算法,并介紹一下使用過程中可能遇到的坑 。
Java加密體系JCAJava抽象了一套密碼算法框架JCA(Java Cryptography Architecture),在此框架中定義了一套接口與類,以規范Java平臺密碼算法的實現 , 而Sun,SunRsaSign,SunJCE這些則是一個個JCA的實現Provider,以實現具體的密碼算法,這有點像List與ArrayList、LinkedList的關系一樣,Java開發者只需要使用JCA即可,而不用管具體是怎么實現的 。
JCA里定義了一系列類,如Cipher、MessageDigest、MAC、Signature等,分別用于實現加密、密碼學哈希、認證碼、數字簽名等算法,一起來看看吧!
對稱加密對稱加密算法 , 使用Cipher類即可 , 以廣泛使用的AES為例 , 如下:
public byte[] encrypt(byte[] data, Key key) {try {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");byte[] iv = SecureRandoms.randBytes(cipher.getBlockSize());//初始化密鑰與加密參數ivcipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));//加密byte[] encryptBytes = cipher.doFinal(data);//將iv與密文拼在一起ByteArrayOutputStream baos = new ByteArrayOutputStream(iv.length + encryptBytes.length);baos.write(iv);baos.write(encryptBytes);return baos.toByteArray();} catch (Exception e) {return ExceptionUtils.rethrow(e);}}public byte[] decrypt(byte[] data, Key key) {try {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//獲取密文前面的ivIvParameterSpec ivSpec = new IvParameterSpec(data, 0, cipher.getBlockSize());cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);//解密iv后面的密文return cipher.doFinal(data, cipher.getBlockSize(), data.length - cipher.getBlockSize());} catch (Exception e) {return ExceptionUtils.rethrow(e);}}如上,對稱加密主要使用Cipher , 不管是AES還是DES,Cipher.getInstance()傳入不同的算法名稱即可 , 這里的Key參數就是加密時使用的密鑰 , 稍后會介紹它是怎么來的 , 暫時先忽略它 。另外,為了使得每次加密出來的密文不同,我使用了隨機的iv向量,并將iv向量拼接在了密文前面 。
注:如果某個算法名稱,如上面的AES/CBC/PKCS5Padding , 你不知道它在JCA中的標準名稱是什么,可以到 https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html 中查詢即可 。
非對稱加密非對稱加密同樣是使用Cipher類,只是傳入的密鑰對象不同 , 以RSA算法為例,如下:
public byte[] encryptByPublicKey(byte[] data, PublicKey publicKey){try{Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}catch (Exception e) {throw Errors.toRuntimeException(e);}}public byte[] decryptByPrivateKey(byte[] data, PrivateKey privateKey){try{Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(data);}catch (Exception e) {throw Errors.toRuntimeException(e);}}一般來說應使用公鑰加密,私鑰解密,但其實反過來也是可以的,這里的PublicKey與PrivateKey也先忽略,后面會介紹它怎么來的 。
密碼學哈希密碼學哈希算法包括MD5、SHA1、SHA256等,在JCA中都使用MessageDigest類即可,如下:
public static String sha256(byte[] bytes) throws NoSuchAlgorithmException {MessageDigest digest = MessageDigest.getInstance("SHA-256");digest.update(bytes);return Hex.encodeHexString(digest.digest());}消息認證碼消息認證碼使用Mac類實現,以常見的HMAC搭配SHA256為例,如下:
public byte[] digest(byte[] data, Key key) throws InvalidKeyException, NoSuchAlgorithmException{Mac mac = Mac.getInstance("HmacSHA256");mac.init(key);return mac.doFinal(data);}數字簽名數字簽名使用Signature類實現 , 以RSA搭配SHA256為例,如下:
public byte[] sign(byte[] data, PrivateKey privateKey) {try {Signature signature = Signature.getInstance("SHA256withRSA");signature.initSign(privateKey);signature.update(data);return signature.sign();} catch (Exception e) {return ExceptionUtils.rethrow(e);}}public boolean verify(byte[] data, PublicKey publicKey, byte[] sign) {try {Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(publicKey);signature.update(data);return signature.verify(sign);} catch (Exception e) {return ExceptionUtils.rethrow(e);}}密鑰協商算法在JCA中,使用KeyAgreement來調用密鑰協商算法 , 以ECDH協商算法為例,如下:

推薦閱讀