非对称加密:公钥与私钥

1 公钥和私钥介绍

公钥和私钥是非对称加密技术的核心概念,广泛应用于加密通信、数字签名和身份验证等场景。这种加密技术包括两个数学上相关联的密钥:一个公钥和一个私钥。

公钥和私钥作为非对称加密技术的核心,提供了一种安全的方式来加密数据、实现数字签名和进行安全通信。随着信息技术的发展,对加密技术的依赖日益增加,公钥基础设施(PKI)和相关加密技术在确保数字时代安全性和隐私方面发挥着重要作用。不断的技术进步和新挑战的出现,要求不断发展和更新这些加密技术。

1.1 公钥(Public Key)

  • 定义: 公钥是在非对称加密系统中使用的一个密钥,可以安全地公开和广泛分发。

  • 功能: 主要用于加密数据和验证数字签名。在加密过程中,公钥用于加密信息,只有对应的私钥才能解密。

  • 分发: 公钥被设计成可以公开共享,通常通过数字证书的形式分发。

1.2 私钥(Private Key)

  • 定义: 私钥是与公钥成对出现的密钥,应严格保密。

  • 功能: 用于解密通过公钥加密的数据和生成数字签名。在数字签名的场景中,私钥用于生成签名,而公钥用于验证签名。

  • 保密性: 私钥的保密性是整个加密系统安全的关键。

1.3 加密和解密过程

在非对称加密中,加密和解密过程如下:

  • 加密过程: 发送方使用接收方的公钥对消息进行加密,然后将加密后的消息发送给接收方。

  • 解密过程: 接收方使用自己的私钥对收到的加密消息进行解密。

1.4 数字签名和验证

  • 签名过程: 发送方使用自己的私钥对消息的散列(或摘要)进行签名,并将签名附加在消息上发送。

  • 验证过程: 接收方使用发送方的公钥验证签名的真实性和消息的完整性。

1.5 密钥生成和管理

  • 密钥生成: 密钥对由专门的算法生成,如RSA、ECDSA或DSA等。

  • 密钥长度: 密钥的安全性与其长度成正比。通常,密钥长度越长,其安全性越高。

  • 密钥管理: 私钥的安全存储和管理至关重要,常用的方法包括密码保护、硬件安全模块(HSM)等。

1.6 加密算法和标准

  • RSA: 最常用的非对称加密算法之一,适用于加密和数字签名。

  • ECC(椭圆曲线加密): 相比于RSA,ECC在相同的密钥长度下提供更高的安全性。

  • DSA(数字签名算法): 专门用于数字签名的非对称算法。

1.7 应用场景

  • 安全通信: 如HTTPS、SSL/TLS等协议,用于安全地传输数据。

  • 数字签名: 用于证实信息的来源和完整性,广泛应用于软件分发、电子文档签名等。

  • 身份验证: 在多种在线服务和交易中验证用户身份。

  • 数据加密: 用于保护敏感数据的隐私,如电子邮件加密、文件加密等。

1.8 安全性考虑

  • 密钥强度: 密钥的强度取决于其长度和生成算法的复杂性。

  • 密钥泄露风险: 私钥的泄露可能导致整个加密系统的崩溃。

  • 前向保密: 确保即使长期密钥被泄露,也不会危及过去的通信。

1.9 挑战和未来发展

  • 量子计算威胁: 量子计算的发展可能威胁现有的加密算法。

  • 新算法的开发: 寻找对抗量子计算威胁的新加密技术。

  • 易用性: 寻求在保持安全性的同时,简化加密技术的使用和管理。

2 场景化交互

2.1 公钥私钥

(1)鲍勃有两把钥匙,一把是公钥,另一把是私钥。

(2)送给他的朋友们----帕蒂、道格、苏珊----每人一把。

鲍勃把公钥

(3)苏珊要给鲍勃写一封保密的信。她写完后用鲍勃的公钥加密,就可以达到保密的效果。

(4)鲍勃收信后,用私钥解密,就看到了信件内容。这里要强调的是,只要鲍勃的私钥不泄露,这封信就是安全的,即使落在别人手里,也无法解密。

(5)鲍勃给苏珊回信,决定采用"数字签名"。他写完后先用Hash函数,生成信件的摘要(digest)。

(6)然后,鲍勃使用私钥,对这个摘要加密,生成"数字签名"(signature)。

(7)鲍勃将这个签名,附在信件下面,一起发给苏珊。

(8)苏珊收信后,取下数字签名,用鲍勃的公钥解密,得到信件的摘要。由此证明,这封信确实是鲍勃发出的。

(9)苏珊再对信件本身使用Hash函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明这封信未被修改过。

(10)复杂的情况出现了。道格想欺骗苏珊,他偷偷使用了苏珊的电脑,用自己的公钥换走了鲍勃的公钥。此时,苏珊实际拥有的是道格的公钥,但是还以为这是鲍勃的公钥。因此,道格就可以冒充鲍勃,用自己的私钥做成"数字签名",写信给苏珊,让苏珊用假的鲍勃公钥进行解密。

(11)后来,苏珊感觉不对劲,发现自己无法确定公钥是否真的属于鲍勃。她想到了一个办法,要求鲍勃去找"证书中心"(certificate authority,简称CA),为公钥做认证。证书中心用自己的私钥,对鲍勃的公钥和一些相关信息一起加密,生成"数字证书"(Digital Certificate)。

(12)鲍勃拿到数字证书以后,就可以放心了。以后再给苏珊写信,只要在签名的同时,再附上数字证书就行了。

(13)苏珊收信后,用CA的公钥解开数字证书,就可以拿到鲍勃真实的公钥了,然后就能证明"数字签名"是否真的是鲍勃签的。

2.2 数字证书

下面,我们看一个应用"数字证书"的实例:https协议。这个协议主要用于网页加密。

(1)首先,客户端向服务器发出加密请求。

(2)服务器用自己的私钥加密网页以后,连同本身的数字证书,一起发送给客户端。

(3)客户端(浏览器)的"证书管理器",有"受信任的根证书颁发机构"列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。

(4)如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。

(5)如果这张数字证书不是由受信任的机构颁发的,浏览器会发出另一种警告。

(6)数字证书如果是可靠的,客户端就可以使用证书中的服务器公钥,对信息进行加密,然后与服务器交换加密信息。

3 RSA算法

RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
 

package cn.aizichan.utils.digest;  
  
import java.security.Key;  
import java.security.KeyFactory;  
import java.security.KeyPair;  
import java.security.KeyPairGenerator;  
import java.security.PrivateKey;  
import java.security.PublicKey;  
import java.security.interfaces.RSAPrivateKey;  
import java.security.interfaces.RSAPublicKey;  
import java.security.spec.PKCS8EncodedKeySpec;  
import java.security.spec.X509EncodedKeySpec;  
import java.util.HashMap;  
import java.util.Map;  
  
import javax.crypto.Cipher;  
  
public class RSACoder {  
    //非对称密钥算法    
    public static final String KEY_ALGORITHM="RSA";    
    /**  
     * 密钥长度,DH算法的默认密钥长度是1024  
     * 密钥长度必须是64的倍数,在512到65536位之间  
     * */    
    private static final int KEY_SIZE=512;    
    //公钥    
    private static final String PUBLIC_KEY="xiaoxiaorenzhe";    
        
    //私钥    
    private static final String PRIVATE_KEY="dadapangzi";    
      
    /**  
     * 初始化密钥对  
     * @return Map 甲方密钥的Map  
     * */    
    public static Map<String,Object> initKey() throws Exception{    
        //实例化密钥生成器    
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);    
        //初始化密钥生成器    
        keyPairGenerator.initialize(KEY_SIZE);    
        //生成密钥对    
        KeyPair keyPair=keyPairGenerator.generateKeyPair();   
        //甲方公钥    
        RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();    
        System.out.println("系数:"+publicKey.getModulus()+"  加密指数:"+publicKey.getPublicExponent());  
        //甲方私钥    
        RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();   
        System.out.println("系数:"+privateKey.getModulus()+"解密指数:"+privateKey.getPrivateExponent());  
        //将密钥存储在map中    
        Map<String,Object> keyMap=new HashMap<String,Object>();    
        keyMap.put(PUBLIC_KEY, publicKey);    
        keyMap.put(PRIVATE_KEY, privateKey);    
        return keyMap;    
            
    }    
      
    /**  
     * 私钥加密  
     * @param data待加密数据  
     * @param key 密钥  
     * @return byte[] 加密数据  
     * */    
    public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception{    
            
        //取得私钥    
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //生成私钥    
        PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);    
        //数据加密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);    
        return cipher.doFinal(data);    
    }    
      
    /**  
     * 公钥加密  
     * @param data待加密数据  
     * @param key 密钥  
     * @return byte[] 加密数据  
     * */    
    public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{    
            
        //实例化密钥工厂    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //初始化公钥    
        //密钥材料转换    
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);    
        //产生公钥    
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);    
            
        //数据加密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);    
        return cipher.doFinal(data);    
    }    
    /**  
     * 私钥解密  
     * @param data 待解密数据  
     * @param key 密钥  
     * @return byte[] 解密数据  
     * */    
    public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{    
        //取得私钥    
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //生成私钥    
        PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);    
        //数据解密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.DECRYPT_MODE, privateKey);    
        return cipher.doFinal(data);    
    }    
      
    /**  
     * 公钥解密  
     * @param data 待解密数据  
     * @param key 密钥  
     * @return byte[] 解密数据  
     * */    
    public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception{    
            
        //实例化密钥工厂    
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);    
        //初始化公钥    
        //密钥材料转换    
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);    
        //产生公钥    
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);    
        //数据解密    
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());    
        cipher.init(Cipher.DECRYPT_MODE, pubKey);    
        return cipher.doFinal(data);    
    }    
      
    /**  
     * 取得私钥  
     * @param keyMap 密钥map  
     * @return byte[] 私钥  
     * */    
    public static byte[] getPrivateKey(Map<String,Object> keyMap){    
        Key key=(Key)keyMap.get(PRIVATE_KEY);    
        return key.getEncoded();    
    }    
    /**  
     * 取得公钥  
     * @param keyMap 密钥map  
     * @return byte[] 公钥  
     * */    
    public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception{    
        Key key=(Key) keyMap.get(PUBLIC_KEY);   
        return key.getEncoded();    
    }    
    /**  
     * @param args  
     * @throws Exception   
     */    
    public static void main(String[] args) throws Exception {    
        //初始化密钥    
        //生成密钥对    
        Map<String,Object> keyMap=RSACoder.initKey();    
        //公钥    
        byte[] publicKey=RSACoder.getPublicKey(keyMap);  
        //byte[] publicKey = b;  
        //私钥    
        byte[] privateKey=RSACoder.getPrivateKey(keyMap);    
        System.out.println("公钥:"+Base64.encode(publicKey));         
        System.out.println("私钥:"+Base64.encode(privateKey));    
            
        System.out.println("================密钥对构造完毕,甲方将公钥公布给乙方,开始进行加密数据的传输=============");    
        String str="aattaggcctegthththfef/aat.mp4";    
        System.out.println("===========甲方向乙方发送加密数据==============");    
        System.out.println("原文:"+str);    
        //甲方进行数据的加密    
        byte[] code1=RSACoder.encryptByPublicKey(str.getBytes(), publicKey);  
        System.out.println("甲方 使用乙方公钥加密后的数据:"+Base64.encode(code1));    
        System.out.println("===========乙方使用甲方提供的公钥对数据进行解密==============");    
        //乙方进行数据的解密    
        //byte[] decode1=RSACoder.decryptByPublicKey(code1, publicKey);    
        byte[] decode1=RSACoder.decryptByPrivateKey(code1, privateKey);    
        System.out.println("乙方解密后的数据:"+new String(decode1)+"");    
            
        System.out.println("===========反向进行操作,乙方向甲方发送数据==============");    
            
        str="乙方向甲方发送数据RSA算法";    
            
        System.out.println("原文:"+str);    
            
        //乙方使用公钥对数据进行加密    
        byte[] code2=RSACoder.encryptByPublicKey(str.getBytes(), publicKey);    
        System.out.println("===========乙方使用公钥对数据进行加密==============");    
        System.out.println("加密后的数据:"+Base64.encode(code2));    
            
        System.out.println("=============乙方将数据传送给甲方======================");    
        System.out.println("===========甲方使用私钥对数据进行解密==============");    
            
        //甲方使用私钥对数据进行解密    
        byte[] decode2=RSACoder.decryptByPrivateKey(code2, privateKey);    
            
        System.out.println("甲方解密后的数据:"+new String(decode2));   
          
          
    }    
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

源启智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值