Skip to content

Instantly share code, notes, and snippets.

@mnrn
Created May 20, 2020 18:56
Show Gist options
  • Select an option

  • Save mnrn/d662c34c3e36264d9e97cdc8ebb7474a to your computer and use it in GitHub Desktop.

Select an option

Save mnrn/d662c34c3e36264d9e97cdc8ebb7474a to your computer and use it in GitHub Desktop.
/**
* @brief RSA鍵暗号のサンプルコード
* @date 2016/07/03
* @ref techtipshoge.blogspot.com/2014/04/javarsa.html
*/
//********************************************************************************
// パッケージ宣言
//********************************************************************************
package rsakey;
//********************************************************************************
//必要なJavaファイルのインポート
//********************************************************************************
import java.math.BigInteger;
import java.util.Random;
import java.util.Scanner;
//********************************************************************************
// クラスの定義
//********************************************************************************
/**
* @brief RSA鍵暗号のテストプログラム
* @note ASCIIコードに対して暗号化を行います
*/
public class RSA {
/**
* @brief ここからはじまります
* @param[in] args コマンドライン引数
*/
public static void main(String[] args) {
// メッセージ読み込み
System.out.println("Input text");
Scanner sc = new Scanner(System.in);
String msg = sc.nextLine();
// RSAテスト実行
RSA instance = new RSA();
instance.execute(msg);
}
/**
* @brief RSAのテストプログラムを実行します
* @param[in] msg 暗号化するメッセージ
*/
private void execute(String msg) {
// RSA暗号鍵の生成
BigInteger[] keys = generate(KEY_BIT);
// 正確には公開鍵:P = pair(public, common)であり、秘密鍵:S = pair(secret, common)と表される
System.out.println("common : " + keys[COMMON_INDEX].toString(RADIX));
System.out.println("public : " + keys[PUBLIC_INDEX].toString(RADIX));
System.out.println("screte : " + keys[SECRET_INDEX].toString(RADIX));
// テキストの暗号化
String encrypted = encrypt(msg, keys[PUBLIC_INDEX], keys[COMMON_INDEX]);
System.out.println("cipher : " + encrypted);
// テキストの復号化
String decrypted = decrypt(encrypted, keys[SECRET_INDEX], keys[COMMON_INDEX]);
System.out.println("plain : " + decrypted);
}
/**
* @brief RSAの鍵を生成します。
* @param bitlen 共通鍵nの最大ビット長
* @return 鍵の配列
*/
private BigInteger[] generate(int bitlen) {
BigInteger[] keys = new BigInteger[KEYS_NUM];
Random rnd = new Random();
for (;;) {
BigInteger p = BigInteger.probablePrime(bitlen >> 1, rnd); // 確率的素数pを取得
BigInteger q = BigInteger.probablePrime(bitlen >> 1, rnd); // 確率的素数qを取得
if (p.equals(q)) { continue; } // p = qならばやりなおし
// n = pqとしたときのΦ(n)を計算(ただし、ΦはオイラーのΦ関数でΦ(n) = (p - 1)(q - 1))
BigInteger phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
BigInteger e = BigInteger.probablePrime(bitlen, rnd); // Φ(n)と互いに素な奇数eを選ぶ
if (!e.gcd(phi).equals(BigInteger.ONE)) { continue; } // gcd(e, Φ(n)) = 1でなければやりなおし
keys[COMMON_INDEX] = p.multiply(q); // n = pqとする
keys[PUBLIC_INDEX] = e; // eを公開鍵として扱う
keys[SECRET_INDEX] = e.modInverse(phi); // 法Φ(n)の下でのeの逆元dを秘密鍵として扱う
break;
}
return keys;
}
/**
* @brief メッセージの暗号化を行う
* @note RSA公開鍵暗号系において、メッセージMに対し署名を行うことに当たる
* @param msg 元の文章
* @param e 公開鍵
* @param n 公開鍵
* @return 暗号化された文
*/
private String encrypt(String msg, BigInteger e, BigInteger n) {
BigInteger a = encode(msg); // メッセージをBigIntegerへ変換
return a.modPow(e, n).toString(RADIX); // 公開鍵演算 P(M) = M^e mod n
}
/**
* @brief 暗号文に対して復号を行う
* @note RSA公開鍵暗号系において、署名の検証、確認に当たる
* @param ciphertext 暗号文
* @param d 秘密鍵
* @param n 秘密鍵
* @return 復号された文
*/
private String decrypt(String ciphertext, BigInteger d, BigInteger n) {
BigInteger a = new BigInteger(ciphertext, RADIX); // 暗号文をBigIntegerへ変換
return decode(a.modPow(d, n)); // 秘密鍵演算 S(C) = C^d mod n
}
/**
* @brief ASCII文字列をBigIntegerに変換する
* @param msg 変換対象のASCII文字列
* @return 変換されたBigInteger
*/
private BigInteger encode(String msg) {
BigInteger code = BigInteger.ZERO;
for (int i = 0; i < msg.length(); i++) {
code = code.multiply(BigInteger.valueOf(CHAR_NUM_MAX));
code = code.add(BigInteger.valueOf(msg.charAt(i)));
}
return code;
}
/**
* @brief 256進数のBigIntegerをASCII文字列に変換する
* @param code 変換対象のBigInteger
* @return 変換されたASCII文字列
*/
private String decode(BigInteger code) {
StringBuilder sb = new StringBuilder();
while (code.compareTo(BigInteger.ZERO) > 0) {
int rem = code.mod(BigInteger.valueOf(CHAR_NUM_MAX)).shortValue();
sb.append((char)rem);
code = code.divide(BigInteger.valueOf(CHAR_NUM_MAX));
}
return sb.reverse().toString();
}
private final int COMMON_INDEX = 0; /**< 鍵の要素nの添字 */
private final int PUBLIC_INDEX = 1; /**< 鍵の要素eの添字 */
private final int SECRET_INDEX = 2; /**< 鍵の要素dの添字 */
private final int KEYS_NUM = 3; /**< 鍵の数 */
private final int RADIX = 16; /**< 16進数で表記します */
private final int KEY_BIT = 1024; /**< 鍵のビット長 */
private final int CHAR_NUM_MAX = 256; /**< ASCII文字の最大数 */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment