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也先忽略 , 后面会介绍它怎么来的 。

经验总结扩展阅读