0


加密与安全_探索非对称加密算法_RSA算法

文章目录

在这里插入图片描述


Pre

加密与安全_探索密钥交换算法(Diffie-Hellman算法) 中我们可以看到,公钥-私钥组成的密钥对是非常有用的加密方式,因为公钥是可以公开的,而私钥是完全保密的,由此奠定了非对称加密的基础。

非对称加密确实是一种非常有用的加密方式,其基础就是公钥和私钥组成的密钥对。公钥可以公开,而私钥则是完全保密的,这种特性为非对称加密提供了很好的安全性。

在非对称加密中,加密和解密使用的不是相同的密钥。只有同一个密钥对中的公钥和私钥才能正常地进行加密和解密操作

因此,如果小明要向小红发送加密文件,他应该首先向小红索取她的公钥。然后,小明使用小红的公钥对文件进行加密,并将加密后的文件发送给小红。由于只有小红持有与公钥对应的私钥,因此只有小红能够使用她的私钥解密这个文件。其他人无法使用公钥解密文件,因为只有私钥的持有者才能解密数据。

这种方式确保了文件在传输过程中的安全性,只有具备私钥的接收方才能解密文件,保护了通信的机密性。


主流的非对称加密算法

主流的非对称加密算法包括:

  1. RSA(Rivest-Shamir-Adleman): RSA是最常用的非对称加密算法之一,它基于大数分解的数学难题。RSA算法可以用于加密、数字签名和密钥交换等场景,广泛应用于网络通信、数据传输和身份认证等领域。
  2. DSA(Digital Signature Algorithm): DSA是一种数字签名算法,专门用于生成和验证数字签名,常用于身份认证、数据完整性验证等场景。DSA算法基于离散对数的数学难题,相对于RSA算法,它的加密和解密速度更快。
  3. ECC(Elliptic Curve Cryptography): ECC是一种基于椭圆曲线的非对称加密算法,具有与RSA相当的安全性,但在密钥长度较短的情况下提供了更高的安全性,因此在资源受限的环境下更加适用。
  4. ElGamal: ElGamal是一种基于离散对数的非对称加密算法,主要用于密钥交换和加密通信。与RSA类似,ElGamal算法也可以用于加密和数字签名,但相对于RSA,ElGamal算法在实现和使用上更为复杂。

这些非对称加密算法在不同的场景下有着各自的优缺点和适用性,选择合适的算法取决于具体的安全需求、性能要求和应用环境。

在这里插入图片描述


典型算法:RSA

非对称加密的典型算法就是RSA算法,它是由Ron Rivest、Adi Shamir和Leonard Adleman这三位密码学家共同发明的,因此用他们三人的姓的首字母缩写表示。

相比对称加密,非对称加密有显著的优点。对称加密需要在通信双方之间协商共享密钥,而非对称加密则可以安全地公开各自的公钥。

  • 在N个人之间进行通信时,使用非对称加密只需要N个密钥对,每个人只需管理自己的密钥对。
  • 而使用对称加密时,则需要N*(N-1)/2个密钥,因此每个人需要管理N-1个密钥,密钥管理的难度大,并且容易导致密钥泄漏。

非对称加密的缺点就是运算速度非常慢,比对称加密要慢很多。 在实际应用中,通常会将非对称加密和对称加密结合使用,以充分发挥它们各自的优点,并弥补彼此的缺点。

假设小明需要向小红传输加密文件,他们可以采取以下步骤:

  1. 小明和小红首先交换各自的公钥,这可以在安全的通信渠道上完成。
  2. 小明生成一个随机的对称密钥(比如AES口令),然后使用小红的公钥通过RSA算法对这个对称密钥进行加密,得到密文。
  3. 小明将加密后的对称密钥发送给小红。
  4. 小红使用自己的RSA私钥对收到的密文进行解密,得到原始的对称密钥。
  5. 现在,小明和小红都拥有相同的对称密钥,他们可以使用对称加密算法(如AES)来加密和解密通信内容。由于对称加密算法的运算速度快,因此通信双方可以更高效地进行加密通信。

通过这种方式,非对称加密用于安全地传输对称密钥,而对称加密用于加密和解密实际的通信内容,既保证了安全性,又提高了效率。


Code

packagecom.artisan.securityalgjava.rsa;importjavax.crypto.Cipher;importjava.security.*;importjava.util.Base64;/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */publicclassRSAExample{publicstaticvoidmain(String[] args)throwsException{// 生成RSA密钥对KeyPair keyPair =generateRSAKeyPair();// 获取公钥和私钥PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();// 要加密的原始数据String plaintext ="Hello, RSA!";System.out.println("Plaintext: "+ plaintext);// 使用公钥加密数据byte[] encryptedBytes =encryptRSA(plaintext.getBytes(), publicKey);String encryptedText =Base64.getEncoder().encodeToString(encryptedBytes);System.out.println("Encrypted text: "+ encryptedText);// 使用私钥解密数据byte[] decryptedBytes =decryptRSA(Base64.getDecoder().decode(encryptedText), privateKey);String decryptedText =newString(decryptedBytes);System.out.println("Decrypted text: "+ decryptedText);}// 生成RSA密钥对publicstaticKeyPairgenerateRSAKeyPair()throwsNoSuchAlgorithmException{KeyPairGenerator keyPairGenerator =KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);// 设置密钥长度为2048位return keyPairGenerator.generateKeyPair();}// 使用公钥加密数据publicstaticbyte[]encryptRSA(byte[] data,PublicKey publicKey)throwsException{Cipher cipher =Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}// 使用私钥解密数据publicstaticbyte[]decryptRSA(byte[] encryptedData,PrivateKey privateKey)throwsException{Cipher cipher =Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(encryptedData);}}

输出:

Plaintext:Hello,RSA!Encrypted text:CU+9ZlNmH3NR5SZSdpZRQmTyXQLU0SLX1d1ICoi/LjAu6a4lMsVXUfB+STFHglKOTVCEjddCJwoWVGXJDcm/nTqRVtB/qIV3+kt7W4/H2fvLeYf+mgbIyNNMyZU4h7k0rbVSTIdHpmfcV1ToYPNVtYarHQ0EbmD261iKeGBGb9HrprknspsXxfIMAEeKOEFotE/4fkwySCsWatANwOwjivEqZcDBnX/1BlhA9CIP4zd4osUoiRt/wJtBsx58/A+47Lf2wBo7C8YcRRpa2A8HxtxnOkhy0cciVeaAzMtaaiVDWbaBqML3sXu3iP3CDkrZQ2+VmBCTZX35y1fxCZ1/Dg==Decrypted text:Hello,RSA!

packagecom.artisan.securityalgjava.rsa;importjavax.crypto.Cipher;importjava.math.BigInteger;importjava.security.*;/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */publicclassRsaDemo{publicstaticvoidmain(String[] args)throwsException{// 明文:byte[] plain ="Hello, encrypt use RSA".getBytes("UTF-8");// 创建公钥/私钥对Person alice =newPerson("Alice");// 用Alice的公钥加密:byte[] pk = alice.getPublicKey();System.out.println(String.format("public key: %x",newBigInteger(1, pk)));byte[] encrypted = alice.encrypt(plain);System.out.println(String.format("encrypted: %x",newBigInteger(1, encrypted)));// 用Alice的私钥解密:byte[] sk = alice.getPrivateKey();System.out.println(String.format("private key: %x",newBigInteger(1, sk)));byte[] decrypted = alice.decrypt(encrypted);System.out.println(newString(decrypted,"UTF-8"));}}classPerson{String name;// 私钥:PrivateKey sk;// 公钥:PublicKey pk;publicPerson(String name)throwsGeneralSecurityException{this.name = name;// 生成公钥/私钥对:KeyPairGenerator kpGen =KeyPairGenerator.getInstance("RSA");
        kpGen.initialize(1024);KeyPair kp = kpGen.generateKeyPair();this.sk = kp.getPrivate();this.pk = kp.getPublic();}/**
     * 把私钥导出为字节
     * @return
     */publicbyte[]getPrivateKey(){returnthis.sk.getEncoded();}/**
     *  把公钥导出为字节
     * @return
     */publicbyte[]getPublicKey(){returnthis.pk.getEncoded();}/**
     * 用公钥加密
     * @param message
     * @return
     * @throws GeneralSecurityException
     */publicbyte[]encrypt(byte[] message)throwsGeneralSecurityException{Cipher cipher =Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE,this.pk);return cipher.doFinal(message);}/**
     * 用私钥解密
     * @param input
     * @return
     * @throws GeneralSecurityException
     */publicbyte[]decrypt(byte[] input)throwsGeneralSecurityException{Cipher cipher =Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE,this.sk);return cipher.doFinal(input);}}

输出:

public key:30819f300d06092a864886f70d010101050003818d00308189028181008c97547fab56c9af0f54d814581a7d695e0722c7029751e4d05530d28923c45ac29420e8cec253a71043e98dae2139cee1d97e125f73c0b32a91196a7154c3199cf6529942627e50796463fc7ab6c747ab0788fe67d3855c9f9348233277ef68d663c2df1232c5adb6d7d9be0aefe5e6c0bcdda48abf9570d732878b93c5bc6d0203010001
encrypted:24bac571932a8f2c633660493a57e895e404c03824ba8fff87bfaaa655914eaeabd032beed102d24479c21e1c17ccfea5018708da42e28ec7e2f472b36f769f0aa0639bdff985babdbce3a9d357a89dcf31df2b00366f16708245c2a75a3c5d25aedd25207f3204416a6e431f305bd49b90eb0d40d6caed2bb4f068c183fb442
private key:30820275020100300d06092a864886f70d01010105000482025f3082025b020100028181008c97547fab56c9af0f54d814581a7d695e0722c7029751e4d05530d28923c45ac29420e8cec253a71043e98dae2139cee1d97e125f73c0b32a91196a7154c3199cf6529942627e50796463fc7ab6c747ab0788fe67d3855c9f9348233277ef68d663c2df1232c5adb6d7d9be0aefe5e6c0bcdda48abf9570d732878b93c5bc6d02030100010281806b2753f1d2875d449decce9c02e27dbf7738fd1aad30e3ebff954e96c88b88369ca305ca2afc1581f975a966a0d716164630dc53e88872d09b9ae7c2270ab17f80e36bc78532d68216ecb3a62bc4ab84be8b6db08c48568622f2216e29609f3ae6db825c13d503554a923fe62850cd6fcf2221315c98946c3fd47c79f6bc5089024100fcc240d520a5106544a5cc764c9149c35fca005b9af0fcb5999fa5e4b69a1a5ca19f732e5a2633c0ceeceb7cc433e39f5fca0c7c9a1679ff9990029170adfe070241008e64db6f5b7270a69d4082c88db9c8c9909519b535bd8bf898f2fc6f3d7ac00c1fa8d2fa4614cb851f64f7bea021d60e5d27fe5f5aa0c21e0f05ef5f54e314eb0240460aca8e850258ddc73d2ec0a58d2964b3b9b589ad1114e67a10cc96e9a720a104c4bbd55f73f0a9806e14ffb91b2bfbb13ebb61180e1c76a126501fdf9ac7a7024020845bb0045c0fe99c837cda3bb32f6d083d644f836433b0a38ce9a4a58f8087c43b1362dfda23d7d4a18409de1b9bfc4fbdb0532a2907eb415703a0eb8ba7dd02401fee6a8ef7af9c5c723215500003984e5ded1bd31061ce5396bf5b55ab7cdbe8b6024863fd466eb8de13318863f485af479cc66b8d8a858f02b9b3254b0c1562
Hello, encrypt use RSA

RSA的公钥和私钥的恢复

RSA的公钥和私钥都可以通过getEncoded()方法获得以byte[]表示的二进制数据,并根据需要保存到文件中。

伪代码如下:

byte[] pkData =...byte[] skData =...KeyFactory kf =KeyFactory.getInstance("RSA");// 恢复公钥:X509EncodedKeySpec pkSpec =newX509EncodedKeySpec(pkData);PublicKey pk = kf.generatePublic(pkSpec);// 恢复私钥:PKCS8EncodedKeySpec skSpec =newPKCS8EncodedKeySpec(skData);PrivateKey sk = kf.generatePrivate(skSpec);

完整代码:

packagecom.artisan.securityalgjava.rsa;importjava.security.*;importjava.security.spec.*;importjava.util.Base64;/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */publicclassRSAKeyConversionExample{publicstaticvoidmain(String[] args)throwsException{// 生成RSA密钥对KeyPair keyPair =generateRSAKeyPair();// 获取公钥和私钥PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();// 将公钥和私钥转换为byte[]数组byte[] publicKeyBytes = publicKey.getEncoded();byte[] privateKeyBytes = privateKey.getEncoded();// 将byte[]数组转换为Base64编码的字符串方便保存和传输String publicKeyBase64 =Base64.getEncoder().encodeToString(publicKeyBytes);String privateKeyBase64 =Base64.getEncoder().encodeToString(privateKeyBytes);System.out.println("Public key (Base64): "+ publicKeyBase64);System.out.println("Private key (Base64): "+ privateKeyBase64);// 从Base64编码的字符串恢复公钥和私钥PublicKey restoredPublicKey =restorePublicKey(Base64.getDecoder().decode(publicKeyBase64));PrivateKey restoredPrivateKey =restorePrivateKey(Base64.getDecoder().decode(privateKeyBase64));// 验证恢复的公钥和私钥与原始的是否一致System.out.println("Restored public key equals original: "+ publicKey.equals(restoredPublicKey));System.out.println("Restored private key equals original: "+ privateKey.equals(restoredPrivateKey));}// 生成RSA密钥对publicstaticKeyPairgenerateRSAKeyPair()throwsNoSuchAlgorithmException{KeyPairGenerator keyPairGenerator =KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);// 设置密钥长度为2048位return keyPairGenerator.generateKeyPair();}/**
     * 从byte[]数组恢复公钥
     * @param publicKeyBytes
     * @return
     * @throws Exception
     */publicstaticPublicKeyrestorePublicKey(byte[] publicKeyBytes)throwsException{KeyFactory keyFactory =KeyFactory.getInstance("RSA");X509EncodedKeySpec publicKeySpec =newX509EncodedKeySpec(publicKeyBytes);return keyFactory.generatePublic(publicKeySpec);}/**
     * 从byte[]数组恢复私钥
     * @param privateKeyBytes
     * @return
     * @throws Exception
     */publicstaticPrivateKeyrestorePrivateKey(byte[] privateKeyBytes)throwsException{KeyFactory keyFactory =KeyFactory.getInstance("RSA");PKCS8EncodedKeySpec privateKeySpec =newPKCS8EncodedKeySpec(privateKeyBytes);return keyFactory.generatePrivate(privateKeySpec);}}

输出

Public key (Base64):MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApd4mRIUmxWx9+Jrp/Gp06gqRbgsGdy36Dshvrkz5ofiKe6guRfP/swimmsdZItPpfWJNn2BKQzTL32gSiZ5y+uU7EpkEDmg2Z6ip5jb0Dpt0/cTldD7ykG6AMlnpJwoFQXgNTCpgqOOhFRNRPTBLUjeVMeNeJPoVQKipdFTVrUU5NCZSHgvBWjngELmLZDdj1sJ/vCyEol1eg9N1G8c9kcyhbAhSGX7BSq3q/heuOPGjzHVTMJb2mKvGPst7fYdmUyVvW+ovF7AMf8AfemLrdZJ+mxi4dj2X5c2fKcNK32+zfJNhpQMdaLZtbHAAyvSVc6xGxiYYGAuUrFnGiY26XwIDAQAB
Private key (Base64):MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCl3iZEhSbFbH34mun8anTqCpFuCwZ3LfoOyG+uTPmh+Ip7qC5F8/+zCKaax1ki0+l9Yk2fYEpDNMvfaBKJnnL65TsSmQQOaDZnqKnmNvQOm3T9xOV0PvKQboAyWeknCgVBeA1MKmCo46EVE1E9MEtSN5Ux414k+hVAqKl0VNWtRTk0JlIeC8FaOeAQuYtkN2PWwn+8LISiXV6D03Ubxz2RzKFsCFIZfsFKrer+F6448aPMdVMwlvaYq8Y+y3t9h2ZTJW9b6i8XsAx/wB96Yut1kn6bGLh2PZflzZ8pw0rfb7N8k2GlAx1otm1scADK9JVzrEbGJhgYC5SsWcaJjbpfAgMBAAECggEAMndY5Vgt57uOyGk58Bbj46G7hePM384ZWw4ZDMtW2LUqTV1qVtZaYjqrlkQ5FqOrUv7p5ygA8FnL/flISp7vFO9R/eKYnVmP1BI5P1ZRA3DBM8UIm0nbu54jWy6IBdzCpJzGTvpF1p0LkcIC4b8j66wFtNwc9NsyRC4NANwe90ytm6/HrsoUlRgMeJv9QejfA8A3+VrF1Y1ozn7aSuElX6q7tdZ0kNEGN7qVdl1qilmcMiPpMLC5k7J7WpTeVZGeQM3Akm2LnbcAS5QMkSyhSZWj0n3e+kGRdmCBdRRCGQVsk2qeTahYZvtv1hJRe0mUbDEC/DWSDFLJudbSa5GAAQKBgQDxMFGpiQZ5IWrxh4Rh2CPJpZB1UfQjC5NI0kcKx8jXGp/GXoGfpcjmmF7yRg9ASeG1oOioZKdktSo7KRsSLKetG+L3W+pHkPaPMz/Vt788XuWAZKlBUJ0+02czeRjXDXY0B6Ik4uJ9okRuKO4EndWVhT/bSC2f6khergOe6HPqXwKBgQCwDbllyfGsRS0yn31KcNTjG2E9FMh9uhRP+0wcJR1dDqsXimQ1KE1cdWRsGWolA5oXaR8jNtSUc3NhuyYnjSoI/S2Z8VYnKdfDNb8x6pPV1RxCW5gRT2vrRxBnnN9bkI5ABhRKQslmAq+I0mYAueUGU+6c7iwNIfC8U+Kn+9gwAQKBgQCCQqloGdRAKXc7uQgbXAOADYYmhruHDeJe6wppXRswaXWvSi1RztThDZwB1yq3eu+HC7976tipQFrtlrbDKxDoIm6DT8YJHta64l/wigujjFEA9dyfpO04GC7dkuKCiwey9AhzSYIvfirdIAfkwGWxGkUxphrWCk9Jq0vTUBICmwKBgB62djZssW11L/pZ2ninEGyCNUd7nbJZSPvfAhsS2nmGepCDwxGG82AC1r8I+/xzEWmuHBF/mjw/m8xb4r8ZoFCrIk5tzLLOWOakNLOXkazHHcPxyKiUa2ZDIniA5HJL2JUQum9uEUZrh4Xd9o9/3pVpBQJ5hlPQLPgdxje59rABAoGAbXZS1iNDOJCw+FG2YsCxUWl0fqwW41ldT6qplckCZ/oZuMNXdxCI3ZNhS1juo0A9dL4tu1wJqHdenlYlmxcVpXfz65n2mdXIULnW4eQts5qKyxY/DImJbrxi0qrRGLd0C/GMxpChjoWLrT4in87JI9PiuJT8OpNq/kgs/z3V4VQ=Restoredpublic key equals original:trueRestoredprivate key equals original:true

以RSA算法为例,它的密钥有256/512/1024/2048/4096等不同的长度。长度越长,密码强度越大,当然计算速度也越慢

如果修改待加密的byte[]数据的大小,可以发现,使用512bit的RSA加密时,明文长度不能超过53字节,使用1024bit的RSA加密时,明文长度不能超过117字节,这也是为什么使用RSA的时候,总是配合AES一起使用,即用AES加密任意长度的明文,用RSA加密AES口令。

RSA算法的加密和解密操作中,密钥长度会影响可以处理的数据大小。一般来说,RSA加密操作能处理的最大数据块大小取决于密钥长度和填充模式。

在常见的填充模式下(如PKCS#1 v1.5或OAEP填充),RSA加密时需要对明文进行填充以满足算法要求的固定长度。这意味着,即使密钥长度较长,但实际能够加密的明文长度仍然受到限制

对于RSA加密,加密前需要对数据进行填充,以保证数据块的大小不超过密钥长度。填充的过程会增加一定的开销。一般来说,填充过程会使得实际能够加密的明文长度比密钥长度小一些。

具体来说,对于一个RSA密钥,它能够加密的最大数据块大小等于密钥长度减去一些填充的开销。因此,较短的密钥长度会限制加密的数据块大小。

在实际应用中,RSA算法的密钥长度一般选择较大的值(如2048位或更高),以提高安全性。但是,由于RSA算法加密的性能相对较慢,特别是在处理较大数据块时,因此通常不适合直接用于加密大量数据。相反,RSA常常与对称加密算法(如AES)结合使用,以提高性能和安全性。

因此,通常的做法是,使用RSA加密对称密钥(如AES密钥),然后使用对称密钥加密要传输的数据。这样既能保证安全性,又能提高加密和解密的性能。


小结

除了无法防止中间人攻击外,非对称加密算法还有一些其他缺点:

  1. 性能低下: 非对称加密算法的计算复杂度比对称加密算法高很多,特别是在处理大量数据时,性能会受到明显影响。因此,非对称加密算法通常用于密钥交换和数字签名等场景,而不适合直接加密大量数据。
  2. 密钥长度限制: 非对称加密算法的密钥长度会直接影响其安全性,通常需要选择较长的密钥长度以确保安全性。然而,较长的密钥长度会导致加密和解密的速度变慢,从而增加了计算的开销。
  3. 密钥管理复杂: 非对称加密算法需要管理公钥和私钥,密钥的生成、存储、分发和更新都需要一定的机制和流程来保证安全性。特别是在大规模系统中,密钥管理可能会变得非常复杂和困难。
  4. 安全性依赖于实现和使用: 非对称加密算法的安全性取决于其算法的设计和实现,以及密钥的生成和使用方式。如果实现存在漏洞或者密钥管理不当,可能会导致加密系统的安全性受到威胁。

综上所述,虽然非对称加密算法在密钥交换和数字签名等方面具有重要的作用,但其性能和安全性方面存在一些局限性,因此在实际应用中需要根据具体情况综合考虑,选择合适的加密方案。

在这里插入图片描述

标签: 安全 算法 网络

本文转载自: https://blog.csdn.net/yangshangwei/article/details/136407101
版权归原作者 小小工匠 所有, 如有侵权,请联系我们删除。

“加密与安全_探索非对称加密算法_RSA算法”的评论:

还没有评论