公開鍵復号化およびSSL/TLSプロトコルの概要

16500 ワード

公開鍵暗号化は、非対称暗号化とも呼ばれ、暗号学アルゴリズムのタイプであり、この暗号学方法では、1対の鍵が必要であり、1つはプライベート鍵であり、もう1つは公開鍵である.この2つの鍵は数学的に関連している.あるユーザの鍵で暗号化した情報は,そのユーザの復号鍵でしか復号できない.そのうちの1つを知っていれば、もう1つは計算できません.従って、一対の鍵のうちの1つが開示されていれば、他の秘密の性質に危害を及ぼすことはない.
暗号化鍵が公開されている場合、これは秘密鍵所有者に暗号化されたデータをアップロードするために使用され、これは
公開鍵暗号化.
復号鍵が公開されている場合、秘密鍵で暗号化された情報は、公開鍵で復号することができ、ユーザのクライアントは、秘密鍵を持っている側が発行したデータやファイルが完全に正確であることを検証し、受信者は、この情報が確かに秘密鍵を持っている誰かから来ていることを知ることができる.
デジタル署名、公開鍵の形式はデジタル証明書です.
対称鍵暗号化と比較して、公開鍵暗号化は汎用鍵を共有する必要はなく、復号された秘密鍵はいかなるユーザにも送信されない.公開鍵がネット上でキャプチャされても、それに一致する秘密鍵がなければ復号できず、キャプチャされた公開鍵は何の役にも立たない.
しかし、公開鍵暗号化はわずかなデータしか暗号化できないため、完全な暗号体系では、公開鍵暗号化によってプライベート鍵を作成し、対称暗号学によって大量のデータをプライベート鍵で暗号化することが多い.公開鍵暗号化のもう一つの機能であるデジタル署名は、対称鍵暗号化では実現できない.
Javaは公開鍵(RSA)暗号化を実現する
RSA公開鍵と秘密鍵の生成:AliceがBobの個人情報を信頼できないメディアで受信したいと仮定する.彼女は以下の方法で1つの公開鍵と1つの秘密鍵を生成することができます:1.勝手に2つの大きい指数pとqを選択して、pはqに等しくなくて、そのN=p*qです.オーラ関数に基づいて、r=(p-1)(q-1)を求める3.rより小さい整数eを選択し、d.(モジュール反元素が存在し、eとrが互いに質がある場合)4.pとqの記録を破棄する.(N,e)は公開鍵、(N,d)は秘密鍵であり、Aliceは彼の公開鍵(N,e)をBobに伝え、彼女の秘密鍵(N,d)を隠す.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import com.sun.org.apache.xml.internal.security.utils.Base64;  
  
  
public class RSAEncrypt {  
    /** 
     *              
     */  
    private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',  
            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };  
  
    /** 
     *         
     */  
    public static void genKeyPair(String filePath) {  
        // KeyPairGenerator           ,  RSA        
        KeyPairGenerator keyPairGen = null;  
        try {  
            keyPairGen = KeyPairGenerator.getInstance("RSA");  
        } catch (NoSuchAlgorithmException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        //          ,     96-1024   
        keyPairGen.initialize(1024,new SecureRandom());  
        //        ,   keyPair   
        KeyPair keyPair = keyPairGen.generateKeyPair();  
        //       
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
        //       
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
        try {  
            //          
            String publicKeyString = Base64.encode(publicKey.getEncoded());  
            //          
            String privateKeyString = Base64.encode(privateKey.getEncoded());  
            //            
            FileWriter pubfw = new FileWriter(filePath + "/publicKey.keystore");  
            FileWriter prifw = new FileWriter(filePath + "/privateKey.keystore");  
            BufferedWriter pubbw = new BufferedWriter(pubfw);  
            BufferedWriter pribw = new BufferedWriter(prifw);  
            pubbw.write(publicKeyString);  
            pribw.write(privateKeyString);  
            pubbw.flush();  
            pubbw.close();  
            pubfw.close();  
            pribw.flush();  
            pribw.close();  
            prifw.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
    /** 
     *              
     *  
     * @param in 
     *                  
     * @throws Exception 
     *                        
     */  
    public static String loadPublicKeyByFile(String path) throws Exception {  
        try {  
            BufferedReader br = new BufferedReader(new FileReader(path  
                    + "/publicKey.keystore"));  
            String readLine = null;  
            StringBuilder sb = new StringBuilder();  
            while ((readLine = br.readLine()) != null) {  
                sb.append(readLine);  
            }  
            br.close();  
            return sb.toString();  
        } catch (IOException e) {  
            throw new Exception("         ");  
        } catch (NullPointerException e) {  
            throw new Exception("       ");  
        }  
    }  
  
    /** 
     *           
     *  
     * @param publicKeyStr 
     *                    
     * @throws Exception 
     *                        
     */  
    public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)  
            throws Exception {  
        try {  
            byte[] buffer = Base64.decode(publicKeyStr);  
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);  
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("    ");  
        } catch (InvalidKeySpecException e) {  
            throw new Exception("    ");  
        } catch (NullPointerException e) {  
            throw new Exception("      ");  
        }  
    }  
  
    /** 
     *          
     *  
     * @param keyFileName 
     *                  
     * @return      
     * @throws Exception 
     */  
    public static String loadPrivateKeyByFile(String path) throws Exception {  
        try {  
            BufferedReader br = new BufferedReader(new FileReader(path  
                    + "/privateKey.keystore"));  
            String readLine = null;  
            StringBuilder sb = new StringBuilder();  
            while ((readLine = br.readLine()) != null) {  
                sb.append(readLine);  
            }  
            br.close();  
            return sb.toString();  
        } catch (IOException e) {  
            throw new Exception("        ");  
        } catch (NullPointerException e) {  
            throw new Exception("       ");  
        }  
    }  
  
    public static RSAPrivateKey loadPrivateKeyByStr(String privateKeyStr)  
            throws Exception {  
        try {  
            byte[] buffer = Base64.decode(privateKeyStr);  
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);  
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("    ");  
        } catch (InvalidKeySpecException e) {  
            throw new Exception("    ");  
        } catch (NullPointerException e) {  
            throw new Exception("      ");  
        }  
    }  
  
    /** 
     *        
     *  
     * @param publicKey 
     *               
     * @param plainTextData 
     *                 
     * @return 
     * @throws Exception 
     *                        
     */  
    public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)  
            throws Exception {  
        if (publicKey == null) {  
            throw new Exception("      ,    ");  
        }  
        Cipher cipher = null;  
        try {  
            //     RSA  
            cipher = Cipher.getInstance("RSA");  
            // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());  
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
            byte[] output = cipher.doFinal(plainTextData);  
            return output;  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("      ");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("      ,   ");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("      ");  
        } catch (BadPaddingException e) {  
            throw new Exception("       ");  
        }  
    }  
  
    /** 
     *        
     *  
     * @param privateKey 
     *               
     * @param plainTextData 
     *                 
     * @return 
     * @throws Exception 
     *                        
     */  
    public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData)  
            throws Exception {  
        if (privateKey == null) {  
            throw new Exception("      ,    ");  
        }  
        Cipher cipher = null;  
        try {  
            //     RSA  
            cipher = Cipher.getInstance("RSA");  
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);  
            byte[] output = cipher.doFinal(plainTextData);  
            return output;  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("      ");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("      ,   ");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("      ");  
        } catch (BadPaddingException e) {  
            throw new Exception("       ");  
        }  
    }  
  
    /** 
     *        
     *  
     * @param privateKey 
     *               
     * @param cipherData 
     *                 
     * @return    
     * @throws Exception 
     *                        
     */  
    public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData)  
            throws Exception {  
        if (privateKey == null) {  
            throw new Exception("      ,    ");  
        }  
        Cipher cipher = null;  
        try {  
            //     RSA  
            cipher = Cipher.getInstance("RSA");  
            // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());  
            cipher.init(Cipher.DECRYPT_MODE, privateKey);  
            byte[] output = cipher.doFinal(cipherData);  
            return output;  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("      ");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("      ,   ");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("      ");  
        } catch (BadPaddingException e) {  
            throw new Exception("       ");  
        }  
    }  
  
    /** 
     *        
     *  
     * @param publicKey 
     *               
     * @param cipherData 
     *                 
     * @return    
     * @throws Exception 
     *                        
     */  
    public static byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData)  
            throws Exception {  
        if (publicKey == null) {  
            throw new Exception("      ,    ");  
        }  
        Cipher cipher = null;  
        try {  
            //     RSA  
            cipher = Cipher.getInstance("RSA");  
            // cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());  
            cipher.init(Cipher.DECRYPT_MODE, publicKey);  
            byte[] output = cipher.doFinal(cipherData);  
            return output;  
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception("      ");  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return null;  
        } catch (InvalidKeyException e) {  
            throw new Exception("      ,   ");  
        } catch (IllegalBlockSizeException e) {  
            throw new Exception("      ");  
        } catch (BadPaddingException e) {  
            throw new Exception("       ");  
        }  
    }  
  
    /** 
     *              
     *  
     * @param data 
     *                 
     * @return        
     */  
    public static String byteArrayToString(byte[] data) {  
        StringBuilder stringBuilder = new StringBuilder();  
        for (int i = 0; i < data.length; i++) {  
            //                                    
            stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);  
            //                            
            stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);  
            if (i < data.length - 1) {  
                stringBuilder.append(' ');  
            }  
        }  
        return stringBuilder.toString();  
    }  
}  
テストクラス
import com.sun.org.apache.xml.internal.security.utils.Base64; 

public class Main {

	
	public static void main(String[] args) throws Exception{
		String filepath="F:/";
//		RSAEncrypt.genKeyPair(filepath);
		String plainText="        ";
		//        
        byte[] cipherData=RSAEncrypt.encrypt(RSAEncrypt.loadPublicKeyByStr(RSAEncrypt.loadPublicKeyByFile(filepath)),plainText.getBytes());  
        String cipher=Base64.encode(cipherData);  
        //        
        byte[] res=RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile(filepath)), Base64.decode(cipher));  
        String restr=new String(res);  
        System.out.println("  :"+plainText);  
        System.out.println("  :"+cipher);  
        System.out.println("  :"+restr);  
        System.out.println();  
	}
    
}

鍵の割当て
他の暗号化プロセスと同様に、RSAにとって公開鍵を割り当てるプロセスは非常に重要である.公開鍵を割り当てるプロセスは、仲介者の攻撃に抵抗しなければならない.EveがBobに公開鍵を渡し、BobにAliceの公開鍵だと信じさせ、AliceとBobの間の情報伝達を受け取ることができると仮定すると、Bobは自分の公開鍵をBobに伝えることができ、BobはこれがAliceの公開鍵だと思っている.EveはすべてのBobをAliceに渡すメッセージを切り取り、このメッセージを自分の鍵で復号し、このメッセージを読み、このメッセージをAliceの公開鍵で暗号化してAliceに伝えることができます.理論的にはAliceもBobもEveが彼らのニュースを盗聴していることを発見しない.このような攻撃を防止するために、信頼できるサードパーティ機関で証明書を発行するのが一般的です.
TLS/SSLプロトコルの基本構想は,公開鍵暗号化法を採用することであり,すなわち,クライアントはまずサーバ側に公開鍵を要求し,その後公開鍵で情報を暗号化する.サーバは暗号文を受信した後,自分の秘密鍵で復号する.SSL/TLSプロトコルの
基本手順:
(1)クライアントは,公開鍵をサーバに要求し検証する.
(2)双方が協議して「対話鍵」を生成する.
(3)双方は「対話鍵」を用いて暗号化通信を行う.
公開鍵が改ざんされないことを保証する:公開鍵をデジタル証明書に格納します.証明書が信頼できる限り、公開鍵は信頼できる.
時間を短縮:セッションごとにクライアントとサーバが「セッションキー」を生成し、情報を暗号化します.「対話鍵」は対称暗号化であるため、演算速度が非常に速く、サーバ公開鍵は「対話鍵」自体を暗号化するためにのみ使用され、暗号化演算の消費時間が減少する.
1.クライアントからのリクエスト(ClientHello)
まず,クライアントはサーバに暗号化同音の要求を発行し,このステップでクライアントは主にサーバに情報を提供する.
(1)サポートされているプロトコルバージョン
(2)クライアントによって生成された乱数.
(3)サポートする暗号化方法
(4)サポートする圧縮計算
2.サーバ応答(Server Hello)
サーバはクライアント要求を受信すると,クライアントに応答する.サーバの応答:
(1)使用する暗号化通信プロトコルバージョンの確認
(2)1つのサーバが生成した乱数であり、後で「ダイアログキー」を生成するために使用される
(3)使用する暗号化方法の確認
(4)サーバ証明書
3.クライアント応答
クライアントがサーバ応答を受信した後、まずサーバ証明書を検証します.
証明書に問題がない場合、クライアントは証明書からサーバの公開鍵を取り出します.次に、次の3つの情報をサーバに送信します.
(1)乱数.この乱数はサーバ公開鍵で暗号化され,盗聴を防止する.
(2)符号化変更通知は、その後の情報が双方で合意した暗号化方法と鍵から送信されることを示す
(3)クライアント握手通知は,クライアントの握手フェーズが終了したことを示す.サーバ検証を提供するために、前に送信されたすべてのコンテンツのhash値でもあります.
上記第1項の乱数は、握手段階全体に現れる3番目の乱数であり、「pre-master key」とも呼ばれる.その後、クライアントとサーバは同時に3つの乱数を持ち、双方は事前に合意した暗号化方法で、今回のセッションで使用される「セッションキー」をそれぞれ生成します.
3つの乱数:クライアントでもサーバでも乱数が必要で、生成された鍵は毎回同じではありません.SSLプロトコルでは証明書は静的であるため,交渉された鍵のランダム性を保証するためにランダムな要因を導入する必要がある.
RSA鍵交換アルゴリズムの場合、pre-master-key自体は乱数であり、helloメッセージのランダムを加えると、3つの乱数は1つの鍵導出器によって最終的に対称鍵を導出する.
pre-masterの存在は、SSLプロトコルがホストごとに完全にランダムな乱数を生成できることを信頼していないため、乱数がランダムでない場合、pre-master-secretが推測される可能性があり、pre master secretのみを鍵として適用するのは適切ではないため、新しいランダム要素を導入する必要がある.クライアントとサーバにpre master secretの3つの乱数を加えて生成された鍵は容易に推測されず、1つの擬似ランダムは完全にランダムではないかもしれないが、3つの擬似ランダムは非常にランダムに近く、1つの自由度を増加するたびにランダム性が増加するのは1つではない.
4.サーバの最終応答
サーバがクライアントの3番目の乱数pre-master keyを受信した後、今回のセッションを生成するために使用される「セッションキー」を計算します.次に、クライアントに最後に次の情報を送信します.
(1)符号化変更通知は、その後の情報が双方で合意した暗号化方法と鍵で送信されることを示す.
(2)サーバの握手完了通知は,サーバの握手フェーズが終了したことを示す.クライアント検証を提供するために、前に送信されたすべてのコンテンツのhash値でもある.