解剖RSAアルゴリズムの原理とデジタル署名(java実現ソースコード付)
12198 ワード
1.RSAアルゴリズム
概要:
1977年、3人の数学者Rivest、Shamir、Adlemanは非対称暗号化を実現するアルゴリズムを設計した.このアルゴリズムは彼ら3人の名前で命名され、RSAアルゴリズムと呼ばれています.RSA暗号化アルゴリズムは非対称暗号化アルゴリズムである.秘密鍵暗号化公開鍵復号、公開鍵暗号化秘密鍵復号のモードに従う.短いRSAキーだけが強力に破られる可能性があります.鍵の長さが十分長い限り、RSAで暗号化された情報は実際には解読できない.
原理:
素数と指数を簡単に紹介します.
素数:素数は素数とも呼ばれ、1より大きい自然数のうち、1とこの整数自体を除いて、他の自然数では割り切れない数を指す.
互質数:公因数が1の2つの数しかなく、互質数と呼ばれています.
型演算:型演算は余剰演算を求める.「模」は「Mod」の音訳です.モジュール演算に密接に関連する概念の一つは「同余」である.数学的には、2つの整数を同じ正の整数で割って、同じ余数を得ると、2つの整数は同じ余剰になります.
指数演算:指数演算は乗方計算とも呼ばれ、計算結果はべき乗と呼ばれます.nmはnをm回自乗することを指す.nmを乗方と見なす結果を「nのm次べき乗」または「nのm次方」と呼ぶ.ここで,nを「底数」,mを「指数」と呼ぶ.
RSAアルゴリズムは,単純な数論的事実に基づいて,2つの大きな素数を容易に考えるが,その積を因数分解することは極めて困難であるため,積を暗号鍵として公開することができる.
鍵の生成手順:
<1>2つの等しくない指数pとqをランダムに選択する
<2>pとqの積Nを算出する
<3>p-1とq-1の積を算出するφNはオーラ関数とも呼ばれます
<4>整数eをランダムに選択し、eとmは互いに質的であり、0
<5>eのモジュール反転要素dの計算
<6>公開鍵が(N,e)であれば秘密鍵が(N,d)である
暗号解読プロセス:
<1>明文数m(0)を仮定する
<2>mを暗号化c,a.c=m^e mod N
<3>暗号文cをm a.m=c^d mod Nに復号する
JavaでRSAツールクラスをカプセル化する
maven依存をインポートするには:
RSAUTilツールクラス:
テストクラス:
2.デジタル署名
概要
デジタル署名(公開鍵デジタル署名、電子署名などとも呼ばれる)は、紙に書かれたような一般的な物理署名であるが、公開鍵暗号化分野の技術を用いて実現され、デジタル情報を鑑別する方法である.一連のデジタル署名は、通常、署名用と検証用の2つの相補的な演算を定義します.
デジタル署名とは、情報の送信者だけが生み出すことができる他人が偽造できないデジタル列であり、このデジタル列は情報の送信者が情報の真実性を送信する有効な証明でもある.
デジタル署名は非対称鍵暗号化技術とデジタル要約技術の応用である.
ステップ
署名プロセス:
1.鍵ペアの取得(RSA,DSA,ECDSA)
2.hash計算のために署名メッセージを必要とするメッセージの要約.(一般的なメッセージの要約はMD 5,SHA-256,SHA-512など)
3.メッセージの要約を非対称暗号化して署名を生成します.
4.原文と署名および公開鍵を一緒に送信
検証プロセス:
1.受信者はまず原文に対してhash計算を行う
2.送信者公開鍵を使用して署名を解除する
3.両者が同一であることを検証し、同一であれば改ざんされていないことを証明する
コードの例:
HashUtil:
digitalSignature:
RSAUTilを上にひっくり返すと見つかります.
概要:
1977年、3人の数学者Rivest、Shamir、Adlemanは非対称暗号化を実現するアルゴリズムを設計した.このアルゴリズムは彼ら3人の名前で命名され、RSAアルゴリズムと呼ばれています.RSA暗号化アルゴリズムは非対称暗号化アルゴリズムである.秘密鍵暗号化公開鍵復号、公開鍵暗号化秘密鍵復号のモードに従う.短いRSAキーだけが強力に破られる可能性があります.鍵の長さが十分長い限り、RSAで暗号化された情報は実際には解読できない.
原理:
素数と指数を簡単に紹介します.
素数:素数は素数とも呼ばれ、1より大きい自然数のうち、1とこの整数自体を除いて、他の自然数では割り切れない数を指す.
互質数:公因数が1の2つの数しかなく、互質数と呼ばれています.
型演算:型演算は余剰演算を求める.「模」は「Mod」の音訳です.モジュール演算に密接に関連する概念の一つは「同余」である.数学的には、2つの整数を同じ正の整数で割って、同じ余数を得ると、2つの整数は同じ余剰になります.
指数演算:指数演算は乗方計算とも呼ばれ、計算結果はべき乗と呼ばれます.nmはnをm回自乗することを指す.nmを乗方と見なす結果を「nのm次べき乗」または「nのm次方」と呼ぶ.ここで,nを「底数」,mを「指数」と呼ぶ.
RSAアルゴリズムは,単純な数論的事実に基づいて,2つの大きな素数を容易に考えるが,その積を因数分解することは極めて困難であるため,積を暗号鍵として公開することができる.
鍵の生成手順:
<1>2つの等しくない指数pとqをランダムに選択する
<2>pとqの積Nを算出する
<3>p-1とq-1の積を算出するφNはオーラ関数とも呼ばれます
<4>整数eをランダムに選択し、eとmは互いに質的であり、0
<5>eのモジュール反転要素dの計算
<6>公開鍵が(N,e)であれば秘密鍵が(N,d)である
暗号解読プロセス:
<1>明文数m(0)を仮定する
<2>mを暗号化c,a.c=m^e mod N
<3>暗号文cをm a.m=c^d mod Nに復号する
JavaでRSAツールクラスをカプセル化する
maven依存をインポートするには:
junit
junit
4.12
test
bouncycastle
bcprov-jdk16
140
org.apache.commons
commons-lang3
3.3.2
commons-codec
commons-codec
1.11
RSAUTilツールクラス:
public class RSAUtil {
//
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 = "RSAPublicKey";
//
private static final String PRIVATE_KEY = "RSAPrivateKey";
/**
*
*
*/
public static Map initKey() throws Exception {
//
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//
keyPairGenerator.initialize(KEY_SIZE);
//
KeyPair keyPair = keyPairGenerator.generateKeyPair();
//
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// map
Map keyMap = new HashMap();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
*
*/
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);
}
/**
*
*
*/
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);
}
/**
*
*/
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);
}
/**
*
*/
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);
}
/**
*
*/
public static byte[] getPrivateKey(Map keyMap) {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
*
*/
public static byte[] getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
}
テストクラス:
public static void main(String[] args) throws Exception {
//
//
Map keyMap = RSAUtil.initKey();
//
byte[] publicKey = RSAUtil.getPublicKey(keyMap);
//
byte[] privateKey = RSAUtil.getPrivateKey(keyMap);
System.out.println(" :" + Base64.encodeBase64String(publicKey));
System.out.println(" :" + Base64.encodeBase64String(privateKey));
String str = "MIICeAIB";
System.out.println(" :" + str);
//
byte[] code1 = RSAUtil.encryptByPrivateKey(str.getBytes(), privateKey);
System.out.println(" :" + Base64.encodeBase64String(code1));
String a=Base64.encodeBase64String(code1);
byte[] code3=Base64.decodeBase64(a);
//
byte[] decode1 = RSAUtil.decryptByPublicKey(code3, publicKey);
System.out.println(" :" + new String(decode1));
//
byte[] code2 = RSAUtil.encryptByPublicKey(str.getBytes(), publicKey);
System.out.println(" :" + Base64.encodeBase64String(code2));
String code4=Base64.encodeBase64String(code2);
//
byte[] code5=Base64.decodeBase64(code4);
byte[] decode2 = RSAUtil.decryptByPrivateKey(code5, privateKey);
System.out.println(" :" + new String(decode2));
}
2.デジタル署名
概要
デジタル署名(公開鍵デジタル署名、電子署名などとも呼ばれる)は、紙に書かれたような一般的な物理署名であるが、公開鍵暗号化分野の技術を用いて実現され、デジタル情報を鑑別する方法である.一連のデジタル署名は、通常、署名用と検証用の2つの相補的な演算を定義します.
デジタル署名とは、情報の送信者だけが生み出すことができる他人が偽造できないデジタル列であり、このデジタル列は情報の送信者が情報の真実性を送信する有効な証明でもある.
デジタル署名は非対称鍵暗号化技術とデジタル要約技術の応用である.
ステップ
署名プロセス:
1.鍵ペアの取得(RSA,DSA,ECDSA)
2.hash計算のために署名メッセージを必要とするメッセージの要約.(一般的なメッセージの要約はMD 5,SHA-256,SHA-512など)
3.メッセージの要約を非対称暗号化して署名を生成します.
4.原文と署名および公開鍵を一緒に送信
検証プロセス:
1.受信者はまず原文に対してhash計算を行う
2.送信者公開鍵を使用して署名を解除する
3.両者が同一であることを検証し、同一であれば改ざんされていないことを証明する
コードの例:
HashUtil:
package com.core.hash;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
public class HashUtil {
//md5
public static String md5(byte[] data) throws NoSuchAlgorithmException{
MessageDigest md=MessageDigest.getInstance("MD5");
byte[] d= md.digest(data);
return byteToString(d);
}
// 16
public static String byteToString(byte[] data){
StringBuffer sb=new StringBuffer();
for (byte by:data) {
sb.append(Integer.toString((by & 0x0ff)+0x100,16).substring(1));
}
return sb.toString();
}
//sha1
public static String sha1(byte[] data) throws NoSuchAlgorithmException{
MessageDigest md=MessageDigest.getInstance("SHA");
byte[] d= md.digest(data);
return byteToString(d);
}
//sha256
public static String sha256(byte[] data) throws NoSuchAlgorithmException{
MessageDigest md=MessageDigest.getInstance("SHA-256");
byte[] d= md.digest(data);
return byteToString(d);
}
//sha512
public static String sha512(byte[] data) throws NoSuchAlgorithmException{
MessageDigest md=MessageDigest.getInstance("SHA-512");
byte[] d= md.digest(data);
return byteToString(d);
}
//ripemd160
public static String ripemd160(byte[] data) throws NoSuchAlgorithmException{
RIPEMD160Digest r=new RIPEMD160Digest();
r.update(data,0,data.length);
byte[] digest=new byte[r.getDigestSize()];
r.doFinal(digest, 0);
return byteToString(digest);
}
// 16 , hash
public static byte[] hexStr2hexByte(String data){
if(null==data||0==data.length()){
return null;
}
data=(data.length()==1)?"0"+data:data;
byte[] arr=new byte[data.length()/2];
byte[] tmp=data.getBytes();
for (int i = 0; i < tmp.length/2; i++) {
arr[i]=unitByte(tmp[i*2], tmp[i*2+1]);
}
return arr;
}
public static byte unitByte(byte src0,byte src1){
byte b0=Byte.decode("0x"+new String(new byte[]{src0})).byteValue();
b0=(byte)(b0<<4);
byte b1=Byte.decode("0x"+new String(new byte[]{src1})).byteValue();
byte ret=(byte)(b0^b1);
return ret;
}
}
digitalSignature:
package com.core.test;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import com.core.RSA.RSAUtil;
import com.core.hash.HashUtil;
public class digitalSignature {
public static void main(String[] args) {
String str=" ( , , ),"
+ " ( )。"
+ " , ,"
+ " 。"
+ " ,"
+ " ( ) 。 , 。"
+ " , 。"
+ " 。"
+ " RSA、ElGamal、Fiat-Shamir、Guillou- Quisquarter、"
+ "Schnorr、Ong-Schnorr-Shamir 、Des/DSA, 。"
+ " 、 、 、 、 、 、 ,"
+ " 。 , ,"
+ " (DSS)。";
try {
/*
* 1. RSA
*/
Map keyMap = RSAUtil.initKey();
byte[] publicKey = RSAUtil.getPublicKey(keyMap);
byte[] privateKey = RSAUtil.getPrivateKey(keyMap);
/*
* 2. hash,
*/
String hash=HashUtil.md5(str.getBytes());
System.out.println("--------------------------- -------------------------------");
System.out.println(" "+hash);
/*
* 3.
*/
byte[] code1 = RSAUtil.encryptByPrivateKey(hash.getBytes(), privateKey);
System.out.println(" :" + Base64.encodeBase64String(code1));
String a=Base64.encodeBase64String(code1);
System.out.println("---------------------------------- ------------------------------------");
/*
* 4.
*/
System.out.println(" :" +a);
byte[] code3=Base64.decodeBase64(a);
byte[] decode1 = RSAUtil.decryptByPublicKey(code3, publicKey);
String b=new String(decode1);
System.out.println(" :" +b);
/*
* 5. hash,
*/
String hash1=HashUtil.md5(str.getBytes());
System.out.println(" :"+hash1);
if(b.equals(hash1)){
System.out.println(" !");
}else{
System.out.println(" !");
}
System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
}
RSAUTilを上にひっくり返すと見つかります.