首页 > 图灵资讯 > 技术篇>正文

Java enc解密 encrypt java

2023-05-18 09:10:47

1.简介

加密方法分为对称加密和非对称加密,区别在于对称加密只有一个密钥,而非对称加密有两个密钥

  • 对称加解密:enccrypt(明文,密钥)=密文,decrypt(密文,密钥)=明文
  • 非对称加解密:encrypt(明文,公钥)=密文,decrypt(密文,私钥)=明文
2.密钥2.1.密钥格式2.1.1.der

.der密钥以二进制编码,在JAVA中需要以流的形式读取密钥。以下是获取公钥的例子:

/**     * der公钥解密,密文Base64输出       */       public static PublicKey getPublicKeyByDer(InputStream is) throws Exception {       try {           if (certificatefactory == null) {               certificatefactory = CertificateFactory.getInstance("X.509");           }           Certificate cert = certificatefactory.generateCertificate(is);           return cert.getPublicKey();       }finally {           if (is != null) {               is.close();           }       }       }

2.1.2.pem

.pem以"-----BEGIN..."开头, "-----END...最后,内容是BASE64编码。以下是获取公钥的例子:

public static PublicKey getPublicKeyByPem(String publicKey) throws Exception {       KeyFactory keyFactory = KeyFactory.getInstance("RSA");       X509EncodKeySpec keySpec = new X509EncodKeySpec(Base64.getDecoder().decode(publicKey));       return keyFactory.generatePublic(keySpec);   }

2.1.3.PKCS12

.简单地说,P12PKCS#12证书包括证书和私钥,并允许密码保护。 以下是获取私钥的例子:

public static Key getP12Key() throws Exception{       try (InputStream is = new FileInputStream( "xx.p12")) {           if (certificatefactory == null) {               certificatefactory = CertificateFactory.getInstance("X.509");           }           KeyStore keystore = KeyStore.getInstance(PKCS12);           keystore.load(is, “p12证书密码”.toCharArray());           Key key = keystore.getKey(p12证书的别名”, “p12证书密码”.toCharArray());           key.getAlgorithm();//密钥对应的加密算法,可以用在 Cipher.getInstance(key.getAlgorithm())           return key;       }   }

2.1.4.纯字符串

字符串密钥也可以是Base64编码或16进制编码,甚至直接是字符串,找到将密钥转换为byte[]的方法来生成密钥。

可以这样获得RSA密钥:

public static PublicKey getRSAPublicKey(byte[] publicKey) throws Exception {       KeyFactory keyFactory = KeyFactory.getInstance("RSA");       X509EncodKeySpec keySpec = new X509EncodKeySpec(publicKey);       return keyFactory.generatePublic(keySpec);   }

AES密钥可以这样获得:

public static Key getKey(byte[] key) throws Exception {       return new SecretKeySpec(key, "AES");   }

2.2.类型
  • X509EncodedKey
  • PKCS8EncodedKey
  • RSAPublicKey
  • RSAPrivateKey
  • DSAPublicKey
  • DSAPrivateKey
2.3.长度
  • 128bit
  • 256bit JAVA对AES的密钥长度有限制,最多不超过128bit,即16位字符串。如果是256bit的密钥,即32位字符串,可以通过修改JRE文件或使用CryptoJSAES来加密解密。
2.4.密钥加密
  • PBKDF2Withhmachachachacha1PBKDF2(Password-Based Key Derivation Function)它是一种用于导出密钥的函数,常用于生成加密密码。其基本原理是通过伪随机函数(如HMAC函数)将明文和盐值作为输入参数,然后重复操作,最终产生密钥。若重复次数足够大,破解成本就会变高。增加盐值也会增加“彩虹表”攻击的难度。

以下是PBKDF2Withmacsha1JAVA的实现

private static final String DEFAULT_ALGORITHM = PBKDF2Withmacsha1;   private static final int DEFAULT_ITERATIONS = 10000;   private static final int DEFAULT_HASH_SIZE = 128;   private static final byte[] DEFAULT_SALT = new byte[]{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};      public static byte[] hash(String key) throws Exception {       char[] password = key.toCharArray();       return hash(password, DEFAULT_ALGORITHM, DEFAULT_ITERATIONS, DEFAULT_HASH_SIZE, DEFAULT_SALT);   }    /**     * @param password 密钥     * @param algorithm 运算算法     * @param iteration 重复计算的次数     * @param hashSize 密钥的长度预期     * @param salt     盐值     * @return 最后生成的密钥     * @throws Exception 各种异常     */   public static byte[] hash(char[] password, String algorithm, int iteration, int hashSize, byte[] salt) throws Exception {           SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);           PBEKeySpec spec = new PBEKeySpec(password, salt, iteration, hashSize);           return skf.generateSecret(spec).getEncoded();   }

3.加密算法3.1.对称3.1.1.DES

DES是对称加密中常见的一种,全称Data Encryption Standard,也就是说,数据加密标准是一种使用密钥加密的块算法。64位密钥长度(bit),超位数密钥被忽略。所谓对称加密,加密和解密钥是一样的。对称加密通常根据固定长度将待加密字符串分成块。不到一整块,或者最后有一个特殊的填充字符。DES加密解密通常是跨语言的,经常会出现问题。通常是填充方式错误,或编码不一致,或选择加密解密模式(ECB,CBC,CTR,OFB,CFB,NCFB,NOFB)没有相应的原因。常见的填充方式有: "pkcs5","pkcs7","iso10126","ansix923"zero' 类型,包括DES-ECB,DES-CBC,DES-CTR,DES-OFB,DES-CFB

public static byte[] desEncrypt(byte[] data, byte[] key) throws Exception {       Cipher cipher = Cipher.getInstance("DES");       SecretKeySpec secretKeySpec = new SecretKeySpec(key, "DES");       cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);       return cipher.doFinal(data);   }

3.1.2.3DES

3DES(也叫Triplees) DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于在每个数据块中使用三次DES加密算法。密钥长度为128,192(bit),若密码位数小于或等于64位,则加密结果与DES相同。原DES容易破解,新的3DES出现,增加了加密安全性,避免了暴力破解。它也是对称加密,也涉及加密编码和填充。包括3DES-ECB,3DES-CBC,3DES-CTR,3DES-OFB,3DES-CFB

public static byte[] desedeEncrypt(byte[] data, byte[] key) throws Exception {       Cipher cipher = Cipher.getInstance("DESede");       SecretKeySpec secretKeySpec = new SecretKeySpec(key, "DESede");       cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);       return cipher.doFinal(data);   }

3.1.3. AES

AES,高级加密标准(英语:Advanced Encryption Standard,缩写:AES),Rijndael加密法,又称Rijndael加密法,是美国联邦政府采用的区块加密标准。该标准用于替代原始DES,已被世界各地广泛分析和使用。严格地说,AES和Rijndael加密方法并不完全相同(尽管它们可以在实际应用中交换),因为Rijndael加密方法可以支持更大范围的块和密钥长度:AES块长固定为128 密钥长度可为128、192或256,而Rijndael使用的密钥和区块长度可为32位的整数倍,以128位为下限,256比特为上限。包括AES-ECB,AES-CBC,AES-CTR,AES-OFB,AES-CFB

public static byte[] aesEncrypt(byte[] data, byte[] key) throws Exception {       Cipher cipher = Cipher.getInstance("AES");       SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");       cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);       return cipher.doFinal(data);   }

AES的算法模式和填充有以下选择,其中CBC需要偏移量,而ECB不需要偏移量。NoPadding是不填充的。此时,需要手动确保加密或解密的字节数为16倍;PKCS5Padding与PKCS7Padding几乎相同。它可以是通用的。填充的内容是填充字节序列的长度。例如,如果Byte数组的长度为15,则需要填充1位才能达到16,则填充0x1。如果Byte数组的长度为1,150xf需要填充;ZeroPadding用0x0填充。

Cipher.getInstance("AES/CBC/NoPadding");Cipher.getInstance("AES/CBC/PKCS5Padding");Cipher.getInstance("AES/CBC/PKCS7Padding");Cipher.getInstance("AES/CBC/ZeroBytePadding");Cipher.getInstance("AES/ECB/NoPadding");Cipher.getInstance("AES/ECB/PKCS5Padding");Cipher.getInstance("AES/ECB/PKCS7Padding");Cipher.getInstance("AES/ECB/ZeroBytePadding");

此外,AES的密钥长度分别为128byte、192byte、256byte对应的字符串长度分别为16位、24位和32位。当密钥大于128byte,即16位字符串长度时,代码会抛出java.security.InvalidKeyException: Illegal key size or default parameters。Illegal key size or default parameters是指密钥长度有限,java运行时环境读取有限的policy文件。文件位于${java_home}/jre/lib/security,这一限制是由于美国对软件出口的控制。有两种解决方案

- 替换${java_home}/jre/lib/security/ 下面的local_policy.jar和US_export_policy.jar。- 使用CryptoJs,这是谷歌开源的AES加解密库,用Js实现,速度和本地JDK差不多,除了第一次加载Js文件外,还需要额外的时间。

3.1.4.RC4

RC4加密算法是RSA三人组的头号人物Ron 1987年Rivest设计的密钥长度可变流加密算法簇。该算法的速度可以达到DES加密的10倍左右,并且具有高水平的非线性。其算法于1994年9月在互联网上发布。由于RC4算法采用xor加密,一旦子密钥序列重复,密文可能会被破解。RC4作为一种旧的验证和加密算法,很容易被黑客攻击,现在逐渐不推荐使用。

public static byte[] rc4Encrypt(byte[] data, byte[] key) throws Exception {       Cipher cipher = Cipher.getInstance(RC4);       SecretKeySpec secretKeySpec = new SecretKeySpec(key, "ARCFOUR");       cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);       return cipher.doFinal(data);   }

3.2.非对称3.2.1. RSA

加解密钥不一致,一般私钥不公开,使用公钥加密,私钥解密,使用私钥加密,公钥可以解密。与AES不同,每次加密的结果都是不同的。需要进行分组加密,RSA加密每组最多117个byte,每组最多128个byte。

public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {       Cipher cipher = Cipher.getInstance("RSA");       KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);       X509EncodKeySpec keySpec = new X509EncodKeySpec(publicKey);       PublicKey key = keyFactory.generatePublic(keySpec);       cipher.init(Cipher.ENCRYPT_MODE, key);       //执行分组加密操作,每组RSA加密最多长度为117       int segment = 117;       int inputLen = data.length;       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {           int offSet = 0;           byte[] cache;           int i = 0;           // 加密数据分段           while (inputLen - offSet > 0) {               if (inputLen - offSet > segment) {                   cache = cipher.doFinal(data, offSet, segment);               } else {                   cache = cipher.doFinal(data, offSet, inputLen - offSet);               }               out.write(cache, 0, cache.length);               i++;               offSet = i * segment;           }           return out.toByteArray();       }   }  public static byte[] encryptByPrivateKey(byte[] data, byte[] publicKey) throws Exception {       Cipher cipher = Cipher.getInstance("RSA");       KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);       X509EncodKeySpec keySpec = new X509EncodKeySpec(publicKey);       PrivateKey key = keyFactory.generatePrivate(keySpec);       cipher.init(Cipher.ENCRYPT_MODE, key);       //执行分组加密操作,每组RSA加密最多长度为117       int segment = 117;       int inputLen = data.length;       try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {           int offSet = 0;           byte[] cache;           int i = 0;           // 加密数据分段           while (inputLen - offSet > 0) {               if (inputLen - offSet > segment) {                   cache = cipher.doFinal(data, offSet, segment);               } else {                   cache = cipher.doFinal(data, offSet, inputLen - offSet);               }               out.write(cache, 0, cache.length);               i++;               offSet = i * segment;           }           return out.toByteArray();       }   }

3.3.补充额外算法

添加BouncyCastle的依赖性,在程序初始化时调用一次

Security.addProvider(new BouncyCastleProvider());

可以在Cipher.getInstance在方法中获得更多的加密算法。

4.签名4.1.算法4.1.1.SHA1withRSA

/**     * RSA签名     *     * @param content   待签名数据     * @param privateKey 商户私钥     * @param encode     字符集编码     * @return 使用Base64编码的签名值     */   public static String sign(String content, String privateKey, String encode) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, UnsupportedEncodingException, SignatureException {       PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey));        KeyFactory keyFactory = KeyFactory.getInstance("RSA");       PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);        java.security.Signature signature = java.security.Signature.getInstance(SHA256withRSA);        signature.initSign(priKey);       signature.update(content.getBytes());        byte[] signed = signature.sign();       return Base64.encode(signed);   }

4.1.2. 其他通用私钥签名

/**     * 底层操作私钥签名     *     * @param algorithm NONEwithRSA     *                   MD2withRSA,MD5withRSA     *                   SHA1withRSA,SHA256withRSA ,SHA384withRSA ,SHA512withRSA     *                   NONEwithDSA     *                   SHA1withDSA     *                   NONEwithECDSA ,SHA1withECDSA ,SHA256withECDSA ,SHA384withECDSA ,SHA512withECDSA     * @param data       byte[]     * @param privateKey PrivateKey     * @return byte[]     */   public static byte[] sign(String algorithm, byte[] data, PrivateKey privateKey) throws Exception {       Signature signature = Signature.getInstance(algorithm);       signature.initSign(privateKey);       signature.update(data);       return signature.sign();   }

5.散列
  • SHA1
  • SHA256
  • SHA384
  • SHA512
  • MD2
  • MD5

apache-commons-所有codec的Digestutils都实现了。

本文是转载内容,我们尊重原作者对文章的权利。如有内容错误或侵权行为,请联系我们更正或删除文章。

上一篇 #yyds干货盘点# LeetCode程序员面试金典:从中序与后序遍历序列构造二叉树
下一篇 Java redis分布式锁 redis 分布式锁问题

文章素材均来源于网络,如有侵权,请联系管理员删除。