Java常用的加密算法

一、加密算法分类

加密算法通常分为三类:

对称加密

指加密和解密使用相同密钥的加密算法。对称加密算法的优点在于加解密效率高且易于实现。

不可逆加密

不可逆加密算法的特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有同样输入的输入数据经过同样的不可逆算法才能得到同样的加密数据。

非对称加密

指加密和解密使用不同密钥的加密算法,也称为公私钥加密。

二、加密算法的应用

1.数字签名:进行身份认证和数据完整性验证,主要用到了非对称密钥加密技术与数字摘要技术。

2.数字证书:主要用来确保数字签名才是安全有效的,数字证书由独立的证书发行机构发布。数字证书各不相同,每种证书可提供不同级别的可信度,该证书内包含用户的个人信息和他的公钥信息,同时还附有认证中心的签名信息。

3.MD5:对用户密码进行加密并进行保存。

4.网络数据加密:保障传输的数据安全,即使被截获报文,在没有密匙的情况下也无法得知报文真实内容。

5.SSL协议:在握手阶段使用的是非对称加密,在传输阶段使用的是对称加密,也就是说在SSL上传送的数据是使用对称密钥加密的。同时HTTPS也是由SSL+HTTP协议构建的可进行加密传输、身份认证(确认客户端连接的目标主机是否是真实正确的主机)的网络协议。

三、对称加密算法实现

  • 优点:算法对消息双方公开、计算量小、加密速度快、加密效率高。
  • 缺点:在数据传送前,发送方和接收方必须商定好秘钥,然后双方保存好秘钥。如果一方的秘钥被泄露,那么加密信息就会被破解。

3.1 DES介绍

DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。不过现在已经有点过时了。

Java代码实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

import java.io.UnsupportedEncodingException;

import java.security.SecureRandom;

import javax.crypto.spec.DESKeySpec;

import javax.crypto.SecretKeyFactory;

import javax.crypto.SecretKey;

import javax.crypto.Cipher;

/**

 * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,

 * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,

 * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。

 * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数

 */

public class DesDemo {

    public DesDemo() {

    }

    // 测试

    public static void main(String args[]) {

        // 待加密内容

        String str = "cryptology";

        // 密码,长度要是8的倍数

        String password = "95880288";

        byte[] result;

        try {

            result = DesDemo.encrypt(str.getBytes(), password);

            System.out.println("加密后:" + result);

            byte[] decryResult = DesDemo.decrypt(result, password);

            System.out.println("解密后:" + new String(decryResult));

        } catch (UnsupportedEncodingException e2) {

            // TODO Auto-generated catch block

            e2.printStackTrace();

        } catch (Exception e1) {

            e1.printStackTrace();

        }

    }

    // 直接将如上内容解密

    /**

     * 加密

     *

     * @param datasource

     *            byte[]

     * @param password

     *            String

     * @return byte[]

     */

    public static byte[] encrypt(byte[] datasource, String password) {

        try {

            SecureRandom random = new SecureRandom();

            DESKeySpec desKey = new DESKeySpec(password.getBytes());

            // 创建一个密匙工厂,然后用它把DESKeySpec转换成

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");

            SecretKey securekey = keyFactory.generateSecret(desKey);

            // Cipher对象实际完成加密操作

            Cipher cipher = Cipher.getInstance("DES");

            // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量

            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);

            // 现在,获取数据并加密

            // 正式执行加密操作

            return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作

        } catch (Throwable e) {

            e.printStackTrace();

        }

        return null;

    }

    /**

     * 解密

     *

     * @param src

     *            byte[]

     * @param password

     *            String

     * @return byte[]

     * @throws Exception

     */

    public static byte[] decrypt(byte[] src, String password) throws Exception {

        // DES算法要求有一个可信任的随机数源

        SecureRandom random = new SecureRandom();

        // 创建一个DESKeySpec对象

        DESKeySpec desKey = new DESKeySpec(password.getBytes());

        // 创建一个密匙工厂

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的

                                                                            // Cipher

                                                                            // 对象

        // 将DESKeySpec对象转换成SecretKey对象

        SecretKey securekey = keyFactory.generateSecret(desKey);

        // Cipher对象实际完成解密操作

        Cipher cipher = Cipher.getInstance("DES");

        // 用密匙初始化Cipher对象

        cipher.init(Cipher.DECRYPT_MODE, securekey, random);

        // 真正开始解密操作

        return cipher.doFinal(src);

    }

}

3.2 IDEA介绍

  •  这种算法是在DES算法的基础上发展出来的,类似于三重DES。
  • 发展IDEA也是因为感到DES具有密钥太短等缺点。
  • DEA的密钥为128位,这么长的密钥在今后若干年内应该是安全的。
  • 在实际项目中用到的很少了解即可。

 Java代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

import java.security.Key;

import java.security.Security;

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class IDEADemo {

    public static void main(String args[]) {

        bcIDEA();

    }

    public static void bcIDEA() {

        String src = "www.xttblog.com security idea";

        try {

            Security.addProvider(new BouncyCastleProvider());

              

            //生成key

            KeyGenerator keyGenerator = KeyGenerator.getInstance("IDEA");

            keyGenerator.init(128);

            SecretKey secretKey = keyGenerator.generateKey();

            byte[] keyBytes = secretKey.getEncoded();

              

            //转换密钥

            Key key = new SecretKeySpec(keyBytes, "IDEA");

              

            //加密

            Cipher cipher = Cipher.getInstance("IDEA/ECB/ISO10126Padding");

            cipher.init(Cipher.ENCRYPT_MODE, key);

            byte[] result = cipher.doFinal(src.getBytes());

            System.out.println("bc idea encrypt : " + Base64.encodeBase64String(result));

              

            //解密

            cipher.init(Cipher.DECRYPT_MODE, key);

            result = cipher.doFinal(result);

            System.out.println("bc idea decrypt : " + new String(result));

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

四、不可逆加密算法

  • 优点:不可逆、易计算、特征化
  • 缺点:可能存在散列冲突

4.1 MD5介绍

MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式
(也就是把一个任意长度的字节串变换成一定长的十六进制数字串)。

主要有以下特点:

  • 1.压缩性: 任意长度的数据,算出的MD5值长度都是固定的。
  • 2.容易计算: 从原数据计算出MD5值很容易。
  • 3.抗修改性: 对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 4.强抗碰撞: 已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

Java代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

import java.security.MessageDigest;

//利用JDK提供java.security.MessageDigest类实现MD5算法

public class MD5Demo {

    public static void main(String[] args) {

        System.out.println(getMD5Code("不可逆加密算法"));

    }

    private MD5Demo() {

    }

    // md5加密

    public static String getMD5Code(String message) {

        String md5Str = "";

        try {

            //创建MD5算法消息摘要

            MessageDigest md = MessageDigest.getInstance("MD5");

            //生成的哈希值的字节数组

            byte[] md5Bytes = md.digest(message.getBytes());

            md5Str = bytes2Hex(md5Bytes);

        }catch(Exception e) {

            e.printStackTrace();

        }

        return md5Str;

    }

    // 2进制转16进制

    public static String bytes2Hex(byte[] bytes) {

        StringBuffer result = new StringBuffer();

        int temp;

        try {

            for (int i = 0; i < bytes.length; i++) {

                temp = bytes[i];

                if(temp < 0) {

                    temp += 256;

                }

                if (temp < 16) {

                    result.append("0");

                }

                result.append(Integer.toHexString(temp));

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

        return result.toString();

    }

}

4.2 SHA1介绍

对于长度小于2^64位的消息,SHA1会产生一个160位(40个字符)的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。

SHA1有如下特性:

  • 不可以从消息摘要中复原信息;
  • 两个不同的消息不会产生同样的消息摘要,(但会有1x10 ^ 48分之一的机率出现相同的消息摘要,一般使用时忽略)。

 Java代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

import java.io.UnsupportedEncodingException;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

public class SHA1Demo {

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        System.out.println(getSha1("不可逆加密算法"));

     

    }

    public static String getSha1(String str) {

        if (null == str || 0 == str.length()) {

            return null;

        }

        char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

        try {

            //创建SHA1算法消息摘要对象

            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");

            //使用指定的字节数组更新摘要。

            mdTemp.update(str.getBytes("UTF-8"));

            //生成的哈希值的字节数组

            byte[] md = mdTemp.digest();

            //SHA1算法生成信息摘要关键过程

            int j = md.length;

            char[] buf = new char[j * 2];

            int k = 0;

            for (int i = 0; i < j; i++) {

                byte byte0 = md[i];

                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];

                buf[k++] = hexDigits[byte0 & 0xf];

            }

            return new String(buf);

        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();

        } catch (UnsupportedEncodingException e) {

            e.printStackTrace();

        }

        return "0";

         

    }

}

4.3 HMAC 介绍

HMAC 是密钥相关的 哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用 哈希算法 (MD5、SHA1 等),以 一个密钥 和 一个消息 为输入,生成一个 消息摘要 作为 输出。

HMAC 发送方 和 接收方 都有的 key 进行计算,而没有这把 key 的第三方,则是 无法计算 出正确的 散列值的,这样就可以 防止数据被篡改。

Java代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

import net.pocrd.annotation.NotThreadSafe;

import net.pocrd.define.ConstField;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.crypto.Mac;

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

import java.util.Arrays;

@NotThreadSafe

public class HMacHelper {

    private static final Logger logger = LoggerFactory.getLogger(HMacHelper.class);

    private Mac mac;

    /**

     * MAC算法可选以下多种算法

     * HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512

     */

    private static final String KEY_MAC = "HmacMD5";

    public HMacHelper(String key) {

        try {

            SecretKey secretKey = new SecretKeySpec(key.getBytes(ConstField.UTF8), KEY_MAC);

            mac = Mac.getInstance(secretKey.getAlgorithm());

            mac.init(secretKey);

        } catch (Exception e) {

            logger.error("create hmac helper failed.", e);

        }

    }

    public byte[] sign(byte[] content) {

        return mac.doFinal(content);

    }

    public boolean verify(byte[] signature, byte[] content) {

        try {

            byte[] result = mac.doFinal(content);

            return Arrays.equals(signature, result);

        } catch (Exception e) {

            logger.error("verify sig failed.", e);

        }

        return false;

    }

}

五、非对称加密

  • 优点:非对称加密与对称加密相比其安全性更好,只要私钥不泄露,很难被破解。
  • 缺点:加密和解密花费时间长、速度慢,只适合对少量数据进行加密。

5.1 RSA介绍

RSA是目前最有影响力和最常用的公钥加密算法。它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥

Java代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

import org.apache.commons.codec.binary.Base64;

import java.security.*;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.HashMap;

import java.util.Map;

import javax.crypto.Cipher;

/**

 * Created by humf.需要依赖 commons-codec 包

 */

public class RSADemo {

    public static void main(String[] args) throws Exception {

        Map<String, Key> keyMap = initKey();

        String publicKey = getPublicKey(keyMap);

        String privateKey = getPrivateKey(keyMap);

        System.out.println(keyMap);

        System.out.println("-----------------------------------");

        System.out.println(publicKey);

        System.out.println("-----------------------------------");

        System.out.println(privateKey);

        System.out.println("-----------------------------------");

        byte[] encryptByPrivateKey = encryptByPrivateKey("123456".getBytes(), privateKey);

        byte[] encryptByPublicKey = encryptByPublicKey("123456", publicKey);

        System.out.println(encryptByPrivateKey);

        System.out.println("-----------------------------------");

        System.out.println(encryptByPublicKey);

        System.out.println("-----------------------------------");

        String sign = sign(encryptByPrivateKey, privateKey);

        System.out.println(sign);

        System.out.println("-----------------------------------");

        boolean verify = verify(encryptByPrivateKey, publicKey, sign);

        System.out.println(verify);

        System.out.println("-----------------------------------");

        byte[] decryptByPublicKey = decryptByPublicKey(encryptByPrivateKey, publicKey);

        byte[] decryptByPrivateKey = decryptByPrivateKey(encryptByPublicKey, privateKey);

        System.out.println(decryptByPublicKey);

        System.out.println("-----------------------------------");

        System.out.println(decryptByPrivateKey);

    }

    public static final String KEY_ALGORITHM = "RSA";

    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    private static final String PUBLIC_KEY = "RSAPublicKey";

    private static final String PRIVATE_KEY = "RSAPrivateKey";

    public static byte[] decryptBASE64(String key) {

        return Base64.decodeBase64(key);

    }

    public static String encryptBASE64(byte[] bytes) {

        return Base64.encodeBase64String(bytes);

    }

    /**

     * 用私钥对信息生成数字签名

     *

     * @param data

     *            加密数据

     * @param privateKey

     *            私钥

     * @return

     * @throws Exception

     */

    public static String sign(byte[] data, String privateKey) throws Exception {

        // 解密由base64编码的私钥

        byte[] keyBytes = decryptBASE64(privateKey);

        // 构造PKCS8EncodedKeySpec对象

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取私钥匙对象

        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 用私钥对信息生成数字签名

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

        signature.initSign(priKey);

        signature.update(data);

        return encryptBASE64(signature.sign());

    }

    /**

     * 校验数字签名

     *

     * @param data

     *            加密数据

     * @param publicKey

     *            公钥

     * @param sign

     *            数字签名

     * @return 校验成功返回true 失败返回false

     * @throws Exception

     */

    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {

        // 解密由base64编码的公钥

        byte[] keyBytes = decryptBASE64(publicKey);

        // 构造X509EncodedKeySpec对象

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取公钥匙对象

        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);

        signature.initVerify(pubKey);

        signature.update(data);

        // 验证签名是否正常

        return signature.verify(decryptBASE64(sign));

    }

    public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据解密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 解密<br>

     * 用私钥解密

     *

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPrivateKey(String data, String key) throws Exception {

        return decryptByPrivateKey(decryptBASE64(data), key);

    }

    /**

     * 解密<br>

     * 用公钥解密

     *

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据解密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);

    }

    /**

     * 加密<br>

     * 用公钥加密

     *

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPublicKey(String data, String key) throws Exception {

        // 对公钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data.getBytes());

    }

    /**

     * 加密<br>

     * 用私钥加密

     *

     * @param data

     * @param key

     * @return

     * @throws Exception

     */

    public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {

        // 对密钥解密

        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据加密

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());

        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);

    }

    /**

     * 取得私钥

     *

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {

        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 取得公钥

     *

     * @param keyMap

     * @return

     * @throws Exception

     */

    public static String getPublicKey(Map<String, Key> keyMap) throws Exception {

        Key key = keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());

    }

    /**

     * 初始化密钥

     *

     * @return

     * @throws Exception

     */

    public static Map<String, Key> initKey() throws Exception {

        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);

        keyPairGen.initialize(1024);

        KeyPair keyPair = keyPairGen.generateKeyPair();

        Map<String, Key> keyMap = new HashMap(2);

        keyMap.put(PUBLIC_KEY, keyPair.getPublic());// 公钥

        keyMap.put(PRIVATE_KEY, keyPair.getPrivate());// 私钥

        return keyMap;

    }

}

5.2 ECC 介绍

ECC 也是一种 非对称加密算法,主要优势是在某些情况下,它比其他的方法使用 更小的密钥,比如 RSA 加密算法,提供 相当的或更高等级 的安全级别。不过一个缺点是 加密和解密操作 的实现比其他机制 时间长 (相比 RSA 算法,该算法对 CPU 消耗严重)。

Java代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

import net.pocrd.annotation.NotThreadSafe;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;

import java.io.ByteArrayOutputStream;

import java.security.KeyFactory;

import java.security.Security;

import java.security.Signature;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

@NotThreadSafe

public class EccHelper {

    private static final Logger logger = LoggerFactory.getLogger(EccHelper.class);

    private static final int SIZE = 4096;

    private BCECPublicKey  publicKey;

    private BCECPrivateKey privateKey;

    static {

        Security.addProvider(new BouncyCastleProvider());

    }

    public EccHelper(String publicKey, String privateKey) {

        this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));

    }

    public EccHelper(byte[] publicKey, byte[] privateKey) {

        try {

            KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");

            if (publicKey != null && publicKey.length > 0) {

                this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));

            }

            if (privateKey != null && privateKey.length > 0) {

                this.privateKey = (BCECPrivateKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));

            }

        } catch (ClassCastException e) {

            throw new RuntimeException("", e);

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    public EccHelper(String publicKey) {

        this(Base64Util.decode(publicKey));

    }

    public EccHelper(byte[] publicKey) {

        try {

            KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");

            if (publicKey != null && publicKey.length > 0) {

                this.publicKey = (BCECPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));

            }

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    public byte[] encrypt(byte[] content) {

        if (publicKey == null) {

            throw new RuntimeException("public key is null.");

        }

        try {

            Cipher cipher = Cipher.getInstance("ECIES", "BC");

            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            int size = SIZE;

            ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 45));

            int left = 0;

            for (int i = 0; i < content.length; ) {

                left = content.length - i;

                if (left > size) {

                    cipher.update(content, i, size);

                    i += size;

                } else {

                    cipher.update(content, i, left);

                    i += left;

                }

                baos.write(cipher.doFinal());

            }

            return baos.toByteArray();

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    public byte[] decrypt(byte[] secret) {

        if (privateKey == null) {

            throw new RuntimeException("private key is null.");

        }

        try {

            Cipher cipher = Cipher.getInstance("ECIES", "BC");

            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            int size = SIZE + 45;

            ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size + 44) / (size + 45) * size);

            int left = 0;

            for (int i = 0; i < secret.length; ) {

                left = secret.length - i;

                if (left > size) {

                    cipher.update(secret, i, size);

                    i += size;

                } else {

                    cipher.update(secret, i, left);

                    i += left;

                }

                baos.write(cipher.doFinal());

            }

            return baos.toByteArray();

        } catch (Exception e) {

            logger.error("ecc decrypt failed.", e);

        }

        return null;

    }

    public byte[] sign(byte[] content) {

        if (privateKey == null) {

            throw new RuntimeException("private key is null.");

        }

        try {

            Signature signature = Signature.getInstance("SHA1withECDSA", "BC");

            signature.initSign(privateKey);

            signature.update(content);

            return signature.sign();

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    public boolean verify(byte[] sign, byte[] content) {

        if (publicKey == null) {

            throw new RuntimeException("public key is null.");

        }

        try {

            Signature signature = Signature.getInstance("SHA1withECDSA", "BC");

            signature.initVerify(publicKey);

            signature.update(content);

            return signature.verify(sign);

        } catch (Exception e) {

            logger.error("ecc verify failed.", e);

        }

        return false;

    }

}

 转载:https://www.jb51.net/article/214770.htmicon-default.png?t=M3K6https://www.jb51.net/article/214770.htm

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值