陪玩小程序源码,不容错过的加密算法整理清单
在开发陪玩小程序源码时,可采用的加密算法类型包含:
对称加密
对称加密算法,使用Cipher类即可,以广泛使用的AES为例,如下:
public byte[] encrypt(byte[] data, Key key) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] iv = SecureRandoms.randBytes(cipher.getBlockSize()); //初始化密钥与加密参数iv cipher.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"); //获取密文前面的iv IvParameterSpec 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()传入不同的算法名称即可。
另外,为了使得每次加密出来的密文不同,我使用了随机的iv向量,并将iv向量拼接在了密文前面。
非对称加密
非对称加密同样是使用Cipher类,只是传入的密钥对象不同,以RSA算法为例,如下:
public byte[] encryptByPublicKey(byte[] data, PublicKey publicKey){ try{ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 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/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); }catch (Exception e) { throw Errors.toRuntimeException(e); } }
一般来说应使用公钥加密,私钥解密,但其实反过来也是可以的。
密码学哈希
密码学哈希算法包括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协商算法为例,如下:
public static void testEcdh() { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1"); keyGen.initialize(ecSpec); // A生成自己的私密信息 KeyPair keyPairA = keyGen.generateKeyPair(); KeyAgreement kaA = KeyAgreement.getInstance("ECDH"); kaA.init(keyPairA.getPrivate()); // B生成自己的私密信息 KeyPair keyPairB = keyGen.generateKeyPair(); KeyAgreement kaB = KeyAgreement.getInstance("ECDH"); kaB.init(keyPairB.getPrivate()); // B收到A发送过来的公用信息,计算出对称密钥 kaB.doPhase(keyPairA.getPublic(), true); byte[] kBA = kaB.generateSecret(); // A收到B发送过来的公开信息,计算对对称密钥 kaA.doPhase(keyPairB.getPublic(), true); byte[] kAB = kaA.generateSecret(); Assert.isTrue(Arrays.equals(kBA, kAB), "协商的对称密钥不一致"); }
基于口令加密PBE
通常,对称加密算法需要使用128位字节的密钥,但这么长的密钥用户是记不住的,用户容易记住的是口令,也即password,但与密钥相比,口令有如下弱点:
1、口令通常较短,这使得直接使用口令加密的强度较差。
2、口令随机性较差,因为用户一般使用较容易记住的东西来生成口令。
为了使得用户能直接使用口令加密,又能最大程度避免口令的弱点,于是PBE(Password Based Encryption)算法诞生,思路如下:
既然密码算法需要密钥,那在加解密前,先使用口令生成密钥,然后再使用此密钥去加解密。
为了弥补口令随机性较差的问题,生成密钥时使用随机盐来混淆口令来产生准密钥,再使用散列函数对准密钥进行多次散列迭代,以生成最终的密钥。
因此,使用PBE算法进行加解密时,除了要提供口令外,还需要提供随机盐(salt)与迭代次数(iteratorCount),如下:
public static byte[] encrypt(byte[] plainBytes, String password, byte[] salt, int iteratorCount) { try { PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray()); SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndTripleDES").generateSecret(keySpec); Cipher cipher = Cipher.getInstance("PBEWithMD5AndTripleDES"); cipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(salt, iteratorCount)); byte[] encryptBytes = cipher.doFinal(plainBytes); byte[] iv = cipher.getIV(); ByteArrayOutputStream baos = new ByteArrayOutputStream(iv.length + encryptBytes.length); baos.write(iv); baos.write(encryptBytes); return baos.toByteArray(); } catch (Exception e) { throw Errors.toRuntimeException(e); } } public static byte[] decrypt(byte[] secretBytes, String password, byte[] salt, int iteratorCount) { try { PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray()); SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndTripleDES").generateSecret(keySpec); Cipher cipher = Cipher.getInstance("PBEWithMD5AndTripleDES"); IvParameterSpec ivParameterSpec = new IvParameterSpec(secretBytes, 0, cipher.getBlockSize()); cipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(salt, iteratorCount, ivParameterSpec)); return cipher.doFinal(secretBytes, cipher.getBlockSize(), secretBytes.length - cipher.getBlockSize()); } catch (Exception e) { throw Errors.toRuntimeException(e); } } public static void main(String[] args) throws Exception { byte[] content = "hello".getBytes(StandardCharsets.UTF_8); byte[] salt = Base64.decode("QBadPOP6/JM="); String password = "password"; byte[] encoded = encrypt(content, password, salt, 1000); System.out.println("密文:" + Base64.encode(encoded)); byte[] plainBytes = decrypt(encoded, password, salt, 1000); System.out.println("明文:" + new String(plainBytes, StandardCharsets.UTF_8)); }
注意,虽然使用PBE加解密数据,都需要使用相同的password、salt、iteratorCount,但这里面只有password是需要保密的,salt与iteratorCount不需要,可以保存在数据库中,比如每个用户注册时给他生成一个随机盐。
到此,JCA密码算法就介绍完了,来回顾一下:
整体来说,JCA对密码算法相关的类设计与封装还是非常清晰简单的!
以上就是陪玩小程序源码,不容错过的加密算法整理清单, 更多内容欢迎关注之后的文章
标签:cipher,getInstance,容错过,Cipher,密钥,byte,data,源码,加密算法 From: https://www.cnblogs.com/yunbaomengnan/p/18286908