자바 RSA 비대 칭 암호 화 알고리즘 구현

공개 키 와 비밀 키
공개 키 와 비밀 키 는 쌍 을 이 루 는 것 이다.일반적으로 우 리 는 공개 키 암호 화,비밀 키 복호화,비밀 키 서명,공개 키 검증 이 라 고 생각한다.어떤 사람 은 비밀 키 암호 화,공개 키 복호화 시 옳지 않다 고 말한다.
공개 키 와 비밀 키 의 생 성 은 여러 가지 방식 이 있 습 니 다.프로그램 을 통 해 생 성 할 수 있 습 니 다(아래 의 구체 적 인 실현).openssl 도 구 를 통 해 생 성 할 수 있 습 니 다.

    #       ,    1024    ,   pem     -out        ,  PKCS1  
    openssl genrsa -out rsa.pem 1024 
    #           ,    Subject Public Key,    PKCS8      
    openssl rsa -in rsa.pem -pubout -out rsa.pub  
RSA 생 성 키 와 비밀 키 는 보통 두 가지 형식 이 있 습 니 다.PKCS 1 과 PKCS 8 은 위의 명령 으로 생 성 된 비밀 키 는 PKCS 1 형식 이 고 공개 키 는 Subject Public Key 입 니 다.보통 PKCS 8 형식 에 맞 춰 비밀 키 를 사용 하기 때문에 PKCS 1 과 PKCS 8 간 의 전환 과 관련 될 수 있 습 니 다.

    # PKCS1       PKCS8    ,       -out        
    openssl pkcs8 -topk8 -inform PEM -in rsa.pem -outform pem -nocrypt -out rsa_pkcs8.pem
    # PKCS8       PKCS1    ,       -out        
    openssl rsa -in rsa_pkcs8.pem -out rsa_pkcs1.pem

    # PKCS1       PKCS8    ,          
    openssl rsa -pubin -in rsa.pub -RSAPublicKey_out
    # PKCS8       PKCS1    ,          
    openssl rsa -RSAPublicKey_in -pubout -in rsa.pub
현실 에서 우 리 는 흔히 pem,crt,pfx 파일 에서 공사 와 비밀 키 를 얻 습 니 다.crt,pfx 의 제작 은 참고 할 수 있 습 니 다.ssl 인증 서 를 간단하게 만 들 고 nginx 와 IIS 에서 사용 합 니 다.또는 기 존:https://pan.baidu.com/s/1MJ5YmuZiLBnf-DfNR_6D7A(추출 코드:c6tj),비밀 번 호 는 모두 123456 입 니 다.
자바 구현
간단 한 설명 소 개 를 위해 저 는 도구 류 를 직접 봉 했 습 니 다.pem,crt,pfx 파일 에서 공사 와 비밀 키 를 가 져 와 야 하기 때문에 제3자 가방 을 참조 하 였 습 니 다.Bouncy Castle 은 pom.xml 에 의존 도 를 직접 추가 할 수 있 습 니 다.

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.68</version>
    </dependency>
또는 뮤 직 비디오 에 다운로드:점프
간단하게 포 장 된 RsaUtil.java:

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Enumeration;

import javax.crypto.Cipher;

import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;

public class RsaUtil {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     *        
     * 
     * @param usePKCS8
     *                PKCS8    
     */
    public static Object[] generateRsaKey(boolean usePKCS8) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
        //    
        keyPairGen.initialize(1024, new SecureRandom());
        //        ,   keyPair 
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); //     
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); //     

        //        PKCS8   
        byte[] publicKeyBytes = publicKey.getEncoded();
        byte[] privateKeyBytes = privateKey.getEncoded();

        if (!usePKCS8) {
            //  PSCK8        PKCS1  
            publicKeyBytes = pkcs8ToPkcs1(false, publicKeyBytes);
            privateKeyBytes = pkcs8ToPkcs1(true, privateKeyBytes);
        }

        return new Object[] { publicKeyBytes, privateKeyBytes };
    }

    /**
     *  Pem       
     * 
     * @param reader
     *               
     * @param pemFileName
     *            pem  
     */
    public static byte[] readFromPem(String pemFileName) throws Exception {
        PemReader pemReader = new PemReader(new FileReader(pemFileName));
        PemObject pemObject = pemReader.readPemObject();
        byte[] publicKey = pemObject.getContent();
        pemReader.close();
        return publicKey;
    }

    /**
     *  Pem      
     * 
     * @param isPrivateKey
     *                 
     * @param buffer
     *              
     * @param pemFileName
     *            pem  
     */
    public static void writeToPem(byte[] buffer, boolean isPrivateKey, String pemFileName) throws Exception {

        PemObject pemObject = new PemObject(isPrivateKey ? "RSA PRIVATE KEY" : "RSA PUBLIC KEY", buffer);
        FileWriter fileWriter = new FileWriter(pemFileName);
        PemWriter pemWriter = new PemWriter(fileWriter);
        pemWriter.writeObject(pemObject);
        pemWriter.close();
    }

    /**
     *  crt      (pkcs8)
     * 
     * @param crtFileName
     *            crt  
     * @return   
     */
    public static byte[] readPublicKeyFromCrt(String crtFileName) throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream(crtFileName));

        PublicKey publicKey = cert.getPublicKey();
        return publicKey.getEncoded();
    }

    /**
     *  pfx       (pkcs8)
     * 
     * @param pfxFileName
     *            pfx  
     * @return    
     */
    public static Object[] readFromPfx(String pfxFileName, String password) throws Exception {
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        char[] passwordChars = null;
        if (password == null || password.equals("")) {
            passwordChars = null;
        } else {
            passwordChars = password.toCharArray();
        }
        keystore.load(new FileInputStream(pfxFileName), passwordChars);
        Enumeration<String> enums = keystore.aliases();

        PrivateKey privateKey = null;
        Certificate certificate = null;
        while (enums.hasMoreElements()) {
            String alias = enums.nextElement();
            System.out.println(alias);
            if (keystore.isKeyEntry(alias)) {
                privateKey = (PrivateKey) keystore.getKey(alias, passwordChars);
                certificate = keystore.getCertificate(alias);
            }
            if (privateKey != null && certificate != null)
                break;
        }
        if (privateKey == null || certificate == null) {
            throw new Exception("fail to read key from pfx");
        }

        PublicKey publicKey = certificate.getPublicKey();
        return new Object[] { publicKey.getEncoded(), privateKey.getEncoded() };
    }

    /**
     * Pkcs8 Pkcs1
     * 
     * @param isPrivateKey
     *                   
     * @param buffer
     *            Pkcs1  
     * @return Pkcs8  
     * @throws Exception
     *                       
     */
    public static byte[] pkcs8ToPkcs1(boolean isPrivateKey, byte[] buffer) throws Exception {
        if (isPrivateKey) {
            PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(buffer);
            return privateKeyInfo.parsePrivateKey().toASN1Primitive().getEncoded();
        } else {
            SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(buffer);
            return subjectPublicKeyInfo.parsePublicKey().toASN1Primitive().getEncoded();
        }
    }

    /**
     * Pkcs1 Pkcs8
     * 
     * @param isPrivateKey
     *                   
     * @param buffer
     *            Pkcs1  
     * @return Pkcs8  
     * @throws Exception
     *                       
     */
    public static byte[] pkcs1ToPkcs8(boolean isPrivateKey, byte[] buffer) throws Exception {
        AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption);
        ASN1Primitive asn1Primitive = ASN1Primitive.fromByteArray(buffer);
        if (isPrivateKey) {
            PrivateKeyInfo privateKeyInfo = new PrivateKeyInfo(algorithmIdentifier, asn1Primitive);
            return privateKeyInfo.getEncoded();
        } else {
            SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, asn1Primitive);
            return subjectPublicKeyInfo.getEncoded();
        }
    }

    /**
     * RSA  
     * 
     * @param usePKCS8
     *                PKCS8    
     * @param publicKey
     *              
     * @return   
     * @throws Exception
     *                       
     */
    public static RSAPublicKey generatePublicKey(boolean usePKCS8, byte[] publicKey) throws Exception {
        KeySpec keySpec;
        if (usePKCS8) {
            // PKCS8  
            keySpec = new X509EncodedKeySpec(publicKey);
        } else {
            // PKCS1  
            DLSequence sequence = (DLSequence) ASN1Primitive.fromByteArray(publicKey);
            BigInteger v1 = ((ASN1Integer) sequence.getObjectAt(0)).getValue();
            BigInteger v2 = ((ASN1Integer) sequence.getObjectAt(1)).getValue();
            keySpec = new RSAPublicKeySpec(v1, v2);
        }

        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME).generatePublic(keySpec);
        return pubKey;
    }

    /**
     * RSA  
     * 
     * @param usePKCS8
     *                PKCS8    
     * @param privateKey
     *              
     * @return   
     * @throws Exception
     *                       
     */
    public static RSAPrivateKey generatePrivateKey(boolean usePKCS8, byte[] privateKey) throws Exception {
        KeySpec keySpec;
        if (usePKCS8) {
            // PKCS8  
            keySpec = new PKCS8EncodedKeySpec(privateKey);
        } else {
            // PKCS1  
            DLSequence sequence = (DLSequence) ASN1Primitive.fromByteArray(privateKey);
            // BigInteger v1= ((ASN1Integer)sequence.getObjectAt(0)).getValue();
            BigInteger v2 = ((ASN1Integer) sequence.getObjectAt(1)).getValue();
            BigInteger v3 = ((ASN1Integer) sequence.getObjectAt(2)).getValue();
            BigInteger v4 = ((ASN1Integer) sequence.getObjectAt(3)).getValue();
            BigInteger v5 = ((ASN1Integer) sequence.getObjectAt(4)).getValue();
            BigInteger v6 = ((ASN1Integer) sequence.getObjectAt(5)).getValue();
            BigInteger v7 = ((ASN1Integer) sequence.getObjectAt(6)).getValue();
            BigInteger v8 = ((ASN1Integer) sequence.getObjectAt(7)).getValue();
            BigInteger v9 = ((ASN1Integer) sequence.getObjectAt(8)).getValue();
            keySpec = new RSAPrivateCrtKeySpec(v2, v3, v4, v5, v6, v7, v8, v9);
        }

        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME).generatePrivate(keySpec);
        return priKey;
    }

    /**
     * RSA    
     * 
     * @param value
     *                 
     * @param publicKey
     *              
     * @return   
     * @throws Exception
     *                       
     */
    public static String rsaEncrypt(String value, RSAPublicKey publicKey) throws Exception {
        if (value == null || value.length() == 0)
            return "";

        // RSA  
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] buffer = cipher.doFinal(value.getBytes("utf-8"));

        //   hex      
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < buffer.length; i++) {
            result.append(String.format("%02x", buffer[i]));
        }
        return result.toString();
    }

    /**
     * RSA    
     * 
     * @param value
     *                 
     * @param privateKey
     *              
     * @return   
     * @throws Exception
     *                       
     */
    public static String rsaDecrypt(String value, RSAPrivateKey privateKey) throws Exception {
        if (value == null || value.length() == 0)
            return "";

        byte[] buffer = new byte[value.length() / 2];
        for (int i = 0; i < buffer.length; i++) {
            buffer[i] = (byte) Integer.parseInt(value.substring(i * 2, i * 2 + 2), 16);
        }

        // RSA  
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        buffer = cipher.doFinal(buffer);
        return new String(buffer, "utf-8");
    }

    /**
     * RSA  
     * 
     * @param value
     *                 
     * @param privateKey
     *              
     * @param halg
     *                , MD5, SHA1, SHA256, SHA384, SHA512 
     * @return   
     * @throws Exception
     *                       
     */
    public static String sign(String value, RSAPrivateKey privateKey, String halg) throws Exception {

        Signature s = Signature.getInstance(halg.toUpperCase().endsWith("WithRSA") ? halg : (halg + "WithRSA"));

        s.initSign(privateKey);
        s.update(value.getBytes("utf-8"));

        byte[] buffer = s.sign();

        //   hex      
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < buffer.length; i++) {
            result.append(String.format("%02x", buffer[i]));
        }
        return result.toString();
    }

    /**
     * RSA    
     * 
     * @param value
     *                 
     * @param publicKey
     *              
     * @param halg
     *                , MD5, SHA1, SHA256, SHA384, SHA512 
     * @return        true,    false
     * @throws Exception
     *                       
     */
    public static boolean verify(String value, RSAPublicKey publicKey, String signature, String halg) throws Exception {
        Signature s = Signature.getInstance(halg.toUpperCase().endsWith("WithRSA") ? halg : (halg + "WithRSA"));
        s.initVerify(publicKey);
        s.update(value.getBytes("utf-8"));

        byte[] buffer = new byte[signature.length() / 2];
        for (int i = 0; i < buffer.length; i++) {
            buffer[i] = (byte) Integer.parseInt(signature.substring(i * 2, i * 2 + 2), 16);
        }

        return s.verify(buffer);
    }

}
공개 키 와 비밀 키 생 성:

    //      
    Object[] rsaKey = RsaUtil.generateRsaKey(usePKCS8); //usePKCS8=true     PKCS8       ,    PKCS1       
    byte[] publicKey = (byte[]) rsaKey[0];
    byte[] privateKey = (byte[]) rsaKey[1];
비밀 키 를 생 성 한 후 저장 해 야 합 니 다.보통 pem 파일 에 저장 합 니 다:

    //    pem  ,filePath     
    RsaUtil.writeToPem(publicKey, false, filePath + "rsa.pub");
    RsaUtil.writeToPem(privateKey, true, filePath + "rsa.pem");
pem 파일 에 저장 할 수 있 습 니 다.물론 pem 파일 에서 도 읽 을 수 있 습 니 다.

    //  Pem       ,filePath     
    byte[] publicKey = RsaUtil.readFromPem(filePath + "rsa.pub");
    byte[] privateKey = RsaUtil.readFromPem(filePath + "rsa.pem");
crt 인증서 에서 공개 키 를 읽 을 수 있 습 니 다.crt 파일 에는 비밀 키 가 포함 되 어 있 지 않 기 때문에 개인 키 를 따로 가 져 와 야 합 니 다.

    //  crt      (crt        ),filePath     
    byte[] publicKey = RsaUtil.readPublicKeyFromCrt(filePath + "demo.crt");
    byte[] privateKey = RsaUtil.readFromPem(filePath + "demo.key");
pfx 파일 에는 공개 키 와 비밀 키 가 포함 되 어 있어 서 쉽게 읽 을 수 있 습 니 다.

    //  pfx       ,filePath     
    Object[] rsaKey = RsaUtil.readFromPfx(filePath + "demo.pfx", "123456");
    byte[] publicKey = (byte[]) rsaKey[0];
    byte[] privateKey = (byte[]) rsaKey[1];
때때로 우 리 는 비밀 키 의 전환 이 필요 할 수도 있다.

    // Pkcs8       Pkcs1    
    publicKey = RsaUtil.pkcs8ToPkcs1(false, publicKey);
    // Pkcs8       Pkcs1    
    privateKey = RsaUtil.pkcs8ToPkcs1(true, privateKey);
    // Pkcs1       Pkcs8    
    publicKey = RsaUtil.pkcs1ToPkcs8(false, publicKey);
    // Pkcs1       Pkcs8    
    privateKey = RsaUtil.pkcs1ToPkcs8(true, privateKey);
공개 키 와 비밀 키 가 있 으 면 암호 화,복호화,서명,서명 검증 등 작업 을 할 수 있 습 니 다.

    RSAPublicKey rsaPublicKey = RsaUtil.generatePublicKey(usePKCS8, publicKey);
    RSAPrivateKey rsaPrivateKey = RsaUtil.generatePrivateKey(usePKCS8, privateKey);

    String encryptText = RsaUtil.rsaEncrypt(text, rsaPublicKey);
    System.out.printf("【%s】  【RSA】   :%s
", text, encryptText); String decryptText = RsaUtil.rsaDecrypt(encryptText, rsaPrivateKey); System.out.printf("【%s】 【RSA】 :%s
", encryptText, decryptText); String signature = RsaUtil.sign(text, rsaPrivateKey, "MD5"); System.out.printf("【%s】 【RSA】 :%s
", text, signature); boolean result = RsaUtil.verify(text, rsaPublicKey, signature, "MD5"); System.out.printf("【%s】 【%s】 【RSA】 :" + result, text, signature);
여기 있 는 전체 demo 코드:

    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    
    public class RsaMain {
    
        public static void main(String[] args) {
            try {
                String text = "     ";
                boolean usePKCS8 = true; // usePKCS8=true     PKCS8       ,    PKCS1       
                String filePath = RsaUtil.class.getClassLoader().getResource("").getPath();
                System.out.printf("    :%s
", filePath);// pem,crt,pfx byte[] publicKey, privateKey;// // Object[] rsaKey = RsaUtil.generateRsaKey(usePKCS8); // usePKCS8=true PKCS8 , PKCS1 publicKey = (byte[]) rsaKey[0]; privateKey = (byte[]) rsaKey[1]; // Pem ,filePath // publicKey = RsaUtil.readFromPem(filePath + "rsa.pub"); // privateKey = RsaUtil.readFromPem(filePath + "rsa.pem"); // pfx ,filePath // Object[] rsaKey = RsaUtil.readFromPfx(filePath + "demo.pfx", // "123456"); // publicKey = (byte[]) rsaKey[0]; // privateKey = (byte[]) rsaKey[1]; // crt (crt ),filePath // publicKey = RsaUtil.readPublicKeyFromCrt(filePath + "demo.crt"); // privateKey = RsaUtil.readFromPem(filePath + "demo.key"); // pem ,filePath RsaUtil.writeToPem(publicKey, false, filePath + "rsa.pub"); RsaUtil.writeToPem(privateKey, true, filePath + "rsa.pem"); // Pkcs8 Pkcs1 publicKey = RsaUtil.pkcs8ToPkcs1(false, publicKey); // Pkcs8 Pkcs1 privateKey = RsaUtil.pkcs8ToPkcs1(true, privateKey); // Pkcs1 Pkcs8 publicKey = RsaUtil.pkcs1ToPkcs8(false, publicKey); // Pkcs1 Pkcs8 privateKey = RsaUtil.pkcs1ToPkcs8(true, privateKey); RSAPublicKey rsaPublicKey = RsaUtil.generatePublicKey(usePKCS8, publicKey); RSAPrivateKey rsaPrivateKey = RsaUtil.generatePrivateKey(usePKCS8, privateKey); String encryptText = RsaUtil.rsaEncrypt(text, rsaPublicKey); System.out.printf("【%s】 【RSA】 :%s
", text, encryptText); String decryptText = RsaUtil.rsaDecrypt(encryptText, rsaPrivateKey); System.out.printf("【%s】 【RSA】 :%s
", encryptText, decryptText); String signature = RsaUtil.sign(text, rsaPrivateKey, "MD5"); System.out.printf("【%s】 【RSA】 :%s
", text, signature); boolean result = RsaUtil.verify(text, rsaPublicKey, signature, "MD5"); System.out.printf("【%s】 【%s】 【RSA】 :" + result, text, signature); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
이상 은 자바 가 RSA 비대 칭 암호 화 알고리즘 을 실현 하 는 상세 한 내용 입 니 다.자바 RSA 비대 칭 암호 화 알고리즘 에 관 한 자 료 는 우리 의 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기