文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java中对称与非对称加密算法原理与使用方法是什么

2023-07-05 14:22

关注

本篇内容介绍了“Java中对称与非对称加密算法原理与使用方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1. 加密概念

密码学是研究编制密码和破译密码的技术科学。以数学为基础,在加密和解密、攻击和防守、矛和盾的对抗过程中交替发展起来。从数学算法的角度看,它包含对称密码算法、非对称密码算法和杂凑算法。

我们先来看下加密中经常提到的一些概念吧!

2. 对称加密

对称加密又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。对称加密的特点是算法公开、加密和解密速度快,适合于对大数据量进行加密。

加密过程如下:明文 + 加密算法 + 私钥 => 密文

解密过程如下:密文 + 解密算法 + 私钥 => 明文

Java中对称与非对称加密算法原理与使用方法是什么

对称加密中用到的密钥叫做私钥,私钥表示个人私有的密钥,即该密钥不能被泄露。 其加密过程中的私钥与解密过程中用到的私钥是同一个密钥,这也是称加密之所以称之为“对称”的原因。由于对称加密的算法是公开的,所以一旦私钥被泄露,那么密文就很容易被破解,所以对称加密的缺点是密钥安全管理困难。

如果你不是很理解,就看这个通俗易懂的例子

甲对乙说,我这有一把锁,以后我们互相传消息,就把消息放盒子里,然后用这个锁锁上再传,这个锁有两把一模一样的钥匙,咱俩一人一把,说完甲把钥匙递给了乙。

3. 非对称加密

非对称加密也叫做公钥加密。非对称加密与对称加密相比,其安全性更好。对称加密的通信双方使用相同的密钥,如果一方的密钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。

被公钥加密过的密文只能被私钥解密,过程如下

明文 + 加密算法 + 公钥 => 密文, 密文 + 解密算法 + 私钥 => 明文

Java中对称与非对称加密算法原理与使用方法是什么

由于加密和解密使用了两个不同的密钥,这就是非对称加密“非对称”的原因。非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。

如果你不是很理解,就看这个通俗易懂的例子

甲对乙说,我这里有A型号锁,对应钥匙A,我给你一大箱子A锁,但是钥匙A不给你,以后你给我发消息就用A锁锁在盒子里给我,然后我自己用钥匙A就能打开看。

乙对甲说,我这里有B型号锁,对应钥匙B,我给你一大箱子B锁,但是钥匙B不给你,以后你给我发消息就用B锁锁在盒子里给我,然后我自己用钥匙B就能打开看。

4. 常见加密算法比较

加密算法分 对称加密 和 非对称加密,其中对称加密算法的加密与解密 密钥相同,非对称加密算法的加密密钥与解密 密钥不同,此外,还有一类 不需要密钥散列算法

常见的 对称加密 算法主要有 DES、3DES、AES 等,常见的 非对称算法 主要有 RSA、ECC 等,散列算法 主要有 SHA-1、MD5 等。

4.1. 散列算法比较

名称安全性速度
MD5
SHA-1

4.2. 对称加密算法比较

名称密钥名称运行速度安全性资源消耗
DES56位较快
3DES112位或168位
AES128、192、256位

4.3. 非对称加密算法比较

名称成熟度运行速度安全性资源消耗
RSA
ECC

对称加密 的 密钥管理比较难,不适合互联网,一般用于内部系统,安全性只能算中等,但加密速度快好 几个数量级 (软件加解密速度至少快 100 倍,每秒可以加解密数 M 比特 数据),适合大数据量的加解密处理。非对称加密 的 密钥容易管理,安全性也较高,但是加密速度比较慢,适合 小数据量 加解密或数据签名。

5. 常见加密算法使用

5.1. MD5算法

MD5 用的是 哈希函数,它的典型应用是对一段信息产生 信息摘要,以 防止被篡改。严格来说,MD5 不是一种 加密算法 而是 摘要算法。无论是多长的输入,MD5 都会输出长度为 128bits 的一个串 (通常用 16 进制 表示为 32 个字符)。

Java使用案例:

public static final byte[] computeMD5(byte[] content) {    try {        MessageDigest md5 = MessageDigest.getInstance("MD5");        return md5.digest(content);    } catch (NoSuchAlgorithmException e) {        throw new RuntimeException(e);    }}

5.2. SHA1算法

SHA1 是和 MD5 一样流行的 消息摘要算法,然而 SHA1 比 MD5 的 安全性更强。对于长度小于 2 ^ 64 位的消息,SHA1 会产生一个 160 位的 消息摘要。基于 MD5、SHA1 的信息摘要特性以及 不可逆 (一般而言),可以被应用在检查 文件完整性 以及 数字签名 等场景。

Java使用案例:

public static byte[] computeSHA1(byte[] content) {    try {        MessageDigest sha1 = MessageDigest.getInstance("SHA1");        return sha1.digest(content);    } catch (NoSuchAlgorithmException e) {        throw new RuntimeException(e);    }}

5.3. HMAC算法

MAC 是密钥相关的 哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用 哈希算法 (MD5、SHA1 等),以 一个密钥 和 一个消息 为输入,生成一个 消息摘要 作为 输出。HMAC 发送方 和 接收方 都有的 key 进行计算,而没有这把 key 的第三方,则是 无法计算 出正确的 散列值的,这样就可以 防止数据被篡改。

Java使用案例:

package net.pocrd.util;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;@NotThreadSafepublic class HMacHelper {    private static final Logger logger = LoggerFactory.getLogger(HMacHelper.class);    private Mac mac;        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;    }}

注意:HMAC 算法实例在 多线程环境 下是 不安全的。但是需要在 多线程访问 时,进行同步的辅助类,使用 ThreadLocal 为 每个线程缓存 一个实例可以避免进行锁操作。

5.4. AES算法

ES、DES、3DES 都是 对称 的 块加密算法,加解密 的过程是 可逆的。常用的有 AES128、AES192、AES256 (默认安装的 JDK 尚不支持 AES256,需要安装对应的 jce 补丁进行升级 jce1.7,jce1.8)。

DES 加密算法是一种 分组密码,以 64 位为 分组对数据 加密,它的 密钥长度 是 56 位,加密解密 用 同一算法。DES 加密算法是对 密钥 进行保密,而 公开算法,包括加密和解密算法。这样,只有掌握了和发送方 相同密钥 的人才能解读由 DES加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是 搜索密钥的编码。对于 56 位长度的 密钥 来说,如果用 穷举法 来进行搜索的话,其运算次数为 2 ^ 56 次。3DES 是基于 DES 的 对称算法,对 一块数据 用 三个不同的密钥 进行 三次加密,强度更高。

AES 加密算法是密码学中的 高级加密标准,该加密算法采用 对称分组密码体制,密钥长度的最少支持为 128 位、 192 位、256 位,分组长度 128 位,算法应易于各种硬件和软件实现。AES 本身就是为了取代 DES 的,AES 具有更好的 安全性、效率 和 灵活性。

Java使用案例:

import net.pocrd.annotation.NotThreadSafe;import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.security.SecureRandom;@NotThreadSafepublic class AesHelper {    private SecretKeySpec keySpec;    private IvParameterSpec iv;    public AesHelper(byte[] aesKey, byte[] iv) {        if (aesKey == null || aesKey.length < 16 || (iv != null && iv.length < 16)) {            throw new RuntimeException("错误的初始密钥");        }        if (iv == null) {            iv = Md5Util.compute(aesKey);        }        keySpec = new SecretKeySpec(aesKey, "AES");        this.iv = new IvParameterSpec(iv);    }    public AesHelper(byte[] aesKey) {        if (aesKey == null || aesKey.length < 16) {            throw new RuntimeException("错误的初始密钥");        }        keySpec = new SecretKeySpec(aesKey, "AES");        this.iv = new IvParameterSpec(Md5Util.compute(aesKey));    }    public byte[] encrypt(byte[] data) {        byte[] result = null;        Cipher cipher = null;        try {            cipher = Cipher.getInstance("AES/CFB/NoPadding");            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);            result = cipher.doFinal(data);        } catch (Exception e) {            throw new RuntimeException(e);        }        return result;    }    public byte[] decrypt(byte[] secret) {        byte[] result = null;        Cipher cipher = null;        try {            cipher = Cipher.getInstance("AES/CFB/NoPadding");            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);            result = cipher.doFinal(secret);        } catch (Exception e) {            throw new RuntimeException(e);        }        return result;    }    public static byte[] randomKey(int size) {        byte[] result = null;        try {            KeyGenerator gen = KeyGenerator.getInstance("AES");            gen.init(size, new SecureRandom());            result = gen.generateKey().getEncoded();        } catch (Exception e) {            throw new RuntimeException(e);        }        return result;    }}

5.5. RSA算法

RSA 加密算法是目前最有影响力的 公钥加密算法,并且被普遍认为是目前 最优秀的公钥方案 之一。RSA 是第一个能同时用于 加密 和 数字签名 的算法,它能够抵抗到目前为止已知的 所有密码攻击,已被 ISO 推荐为公钥数据加密标准。

RSA 加密算法 基于一个十分简单的数论事实:将两个大 素数 相乘十分容易,但想要对其乘积进行 因式分解 却极其困难,因此可以将 乘积 公开作为 加密密钥

Java使用案例:

import net.pocrd.annotation.NotThreadSafe;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.interfaces.RSAPrivateCrtKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;@NotThreadSafepublic class RsaHelper {    private static final Logger logger = LoggerFactory.getLogger(RsaHelper.class);    private RSAPublicKey publicKey;    private RSAPrivateCrtKey privateKey;    static {        // 使用bouncycastle作为加密算法实现        Security.addProvider(new BouncyCastleProvider());     }    public RsaHelper(String publicKey, String privateKey) {        this(Base64Util.decode(publicKey), Base64Util.decode(privateKey));    }    public RsaHelper(byte[] publicKey, byte[] privateKey) {        try {            KeyFactory keyFactory = KeyFactory.getInstance("RSA");            if (publicKey != null && publicKey.length > 0) {                this.publicKey = (RSAPublicKey)keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));            }            if (privateKey != null && privateKey.length > 0) {                this.privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));            }        } catch (Exception e) {            throw new RuntimeException(e);        }    }    public RsaHelper(String publicKey) {        this(Base64Util.decode(publicKey));    }    public RsaHelper(byte[] publicKey) {        try {            KeyFactory keyFactory = KeyFactory.getInstance("RSA");            if (publicKey != null && publicKey.length > 0) {                this.publicKey = (RSAPublicKey)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.");        }        if (content == null) {            return null;        }        try {            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");            cipher.init(Cipher.ENCRYPT_MODE, publicKey);            int size = publicKey.getModulus().bitLength() / 8 - 11;            ByteArrayOutputStream baos = new ByteArrayOutputStream((content.length + size - 1) / size * (size + 11));            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.");        }        if (secret == null) {            return null;        }        try {            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");            cipher.init(Cipher.DECRYPT_MODE, privateKey);            int size = privateKey.getModulus().bitLength() / 8;            ByteArrayOutputStream baos = new ByteArrayOutputStream((secret.length + size - 12) / (size - 11) * 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("rsa decrypt failed.", e);        }        return null;    }    public byte[] sign(byte[] content) {        if (privateKey == null) {            throw new RuntimeException("private key is null.");        }        if (content == null) {            return null;        }        try {            Signature signature = Signature.getInstance("SHA1WithRSA");            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.");        }        if (sign == null || content == null) {            return false;        }        try {            Signature signature = Signature.getInstance("SHA1WithRSA");            signature.initVerify(publicKey);            signature.update(content);            return signature.verify(sign);        } catch (Exception e) {            logger.error("rsa verify failed.", e);        }        return false;    }}

5.6. ECC算法

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

Java使用案例:

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;@NotThreadSafepublic 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;    }}

“Java中对称与非对称加密算法原理与使用方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯