Java8 で書きなおした → JavaSE RSA暗号 Java8
RSA暗号概略 †
- RSA暗号では、原理的に鍵長以上のデータを暗号化できないことのメモ
- ここに出てくる図や表を作るために Javascript でアプリを作ってみた。良かったら遊んでやってください
RSA暗号の基本的な考え方 †
- 平文 x を n乗 したものを 二つの素数の組(p,q)の積(p×q)で割った余りを一覧表にして暗号表を作る
ここでは (p,q)=(3,5) を例に考える。
- この表を見ると定期的に元の平文が現れていることが分かる(ピンクの列)
- n × LCM( p-1 , q-1 ) + 1 行が平文と同じになっている
- LCM (Least Common Multiple。最小公倍数)。LCM(3-1,5-1)=4
- 暗号への応用
- 平文をE乗して暗号化し、暗号文をD乗したらピンクの列に乗るような(E,D)の組を見つける
- 鍵セット = (E,D)
- この鍵セットは逆に使うこともできる
- 平文をD乗して暗号化し、暗号文をE乗してもピンクの列に乗る
公開鍵と秘密鍵 †
- 鍵セットの求め方
- 鍵セットの利用例
- (p,q)=(3,5) のとき、(E,D)=(3,7)は有効な鍵セット。E=3 を秘密鍵、D=7 を公開鍵と呼ぶとすると
- 秘密鍵(3) で暗号化して、公開鍵(7) で復号化
- 公開鍵(7) で暗号化して、秘密鍵(3) で復号化
- 確かに、3 を秘密鍵(3)で暗号化すると 12 になり、12 を公開鍵(7)で復号化すると 3 に戻っている
RSA暗号で暗号化できる平文の長さ †
- RSA暗号は、平文を n乗 して m で割った余りを用いて暗号化するので、mより大きい値を暗号化することはできない
- RSA-???? の鍵長
通常 11byte を Padding に使うので、????で示された bit 長さから、88bit(11byte)を引いたものが鍵長
| 鍵長(Padding含む) | 平文の最大長(=実質的な鍵長) |
| RSA-512 | 512bit(64byte) | 53byte |
| RSA-1024 | 1024bit(128byte) | 117byte |
| RSA-2048 | 2048bit(256byte) | 245byte |
- 長文を暗号化するには
秘密鍵の保存方法 †
- PKCS(Public Key Cryptography Standard)
- DER/PEM
- 鍵の保存方法
| DER | Distinguished Encoding Rules | バイナリ形式 |
| PEM | Privacy Enhanced Mail | DERをBase64でテキスト化したもの |
- 例
- PKCS#8 を DER で保存
- PKCS#12 を PEM で保存
公開鍵の保存方法 †
- X.509の登場人物
| 利用者 | 公開鍵の利用者 |
| サービス提供者 | 公開鍵の提供者 |
| CA(Certification Authority) | 信頼の置ける機関 |
- 利用者は、サービス提供者の提供する公開鍵を使いたいが、サービス提供者を信頼して良いか分からない
- 利用者は、CAを信頼している
- X.509 は、公開鍵 + CAのお墨付き
- X.509の構造
| パラメータ | 例 |
| �� | CA 署名書バージョン | V1 |
| �� | CA 証明書シリアル番号 | 整数 |
| �� | CA 署名アルゴリズム | SHA1 RSA |
| �� | CA 名 | Foo Co.LTD |
| �� | 有効期限 | 2031/12/31 |
| �� | サービス提供者 | Bar Co.LTD |
| �� | 公開鍵アルゴリズム | RSA |
| �� | 公開鍵 | |
| �� | 署名アルゴリズム | ��と同じ(SHA1など) |
| �� | 署名 | encrypt(CA秘密鍵, digest(��,�´↓��きキΝЛ�)) |
- 証明書の確認方法
Java SE での RSA暗号 †
Java SE 5.0 (=Java2 1.5) から、RSA暗号の実装*1が標準で組み込まれるようになりました。
ほかの暗号と同様に、JCAの手順で暗号化・復号化しているので、main() から順に見ていけば分かると思います。
Java 1.4以前で RSA暗号 を扱うためには、RSA暗号の実装を別途準備する必要があります( http://www.bouncycastle.org/ を利用することができます)。
package com.snail.example;
import sun.misc.HexDumpEncoder;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAKey;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
/**
* RSA Examination.
*
* @author kagyuu
* @version $Revision$
*/
public class RSAExam {
/** sources of the example document */
private static String[] WISDOMS = new String[] {
"Insanity: doing the same thing over and over again and expecting different results.",
"Albert Einstein",
"Happiness is nothing more than good health and a bad memory.",
"Albert Schweitzer",
"Our problems are man-made, therefore they may be solved by man.", "J.F.K",
"Obstacles are those frightful things you see when you take your eyes off your goal. ",
"Henry Ford"
};
/** Example plain document */
private static String EXAMPLE = WISDOMS[0] + WISDOMS[1];
/** KEY LENGTH */
private static int KEY_LENGTH = 1024;
/**
* Main Routine.
*
* @param args Commandline Argument
*/
public static void main(String[] args) {
// Create Key Pair
KeyPair keyPair = createKeyPair();
System.out.println("Private Key: "
+ ((RSAKey) keyPair.getPrivate()).getModulus().bitLength() + "bit.");
System.out.println("Public Key: "
+ ((RSAKey) keyPair.getPublic()).getModulus().bitLength() + "bit.");
// Raw data
System.out.println("\nRAW DATA");
byte[] rawText = EXAMPLE.getBytes();
hexDump(rawText);
try {
// Encrypt data
byte[] encryptedText = encrypt(keyPair.getPublic(), rawText);
System.out.println("\nENCRYPTED DATA");
hexDump(encryptedText);
// Decrypt data
byte[] decryptedText = decrypt(keyPair.getPrivate(), encryptedText);
System.out.println("\nDECRYPTED DATA");
hexDump(decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create Key Pair.
*
* @return key pair
*/
private static KeyPair createKeyPair() {
KeyPair keyPair = null;
try {
KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(KEY_LENGTH);
keyPair = keygen.generateKeyPair();
System.out.print("PUBLIC KEY (");
System.out.print(keyPair.getPublic().getAlgorithm() + " ");
System.out.println(keyPair.getPublic().getFormat() + ")");
hexDump(keyPair.getPublic().getEncoded());
System.out.print("\nPRIVATE KEY (");
System.out.print(keyPair.getPrivate().getAlgorithm() + " ");
System.out.println(keyPair.getPrivate().getFormat() + ")");
hexDump(keyPair.getPrivate().getEncoded());
} catch (NoSuchAlgorithmException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
}
return keyPair;
}
/**
* Decrypt data.
*
* @param key decrypt key
* @param data encrypted data
*
* @return decrypted data
*
* @throws InvalidKeyException key is wrong
* @throws IllegalBlockSizeException data is wrong ( too long )
*/
private static byte[] decrypt(Key key, byte[] data)
throws InvalidKeyException, IllegalBlockSizeException {
byte[] decrypted = null;
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
decrypted = cipher.doFinal(data);
} catch (NoSuchAlgorithmException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
} catch (NoSuchPaddingException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
} catch (BadPaddingException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
}
return decrypted;
}
/**
* Encrypt data.
*
* @param key encrypt key
* @param data data
*
* @return encrypted data
*
* @throws InvalidKeyException key is wrong
* @throws IllegalBlockSizeException data is wrong ( too long )
*/
private static byte[] encrypt(Key key, byte[] data)
throws InvalidKeyException, IllegalBlockSizeException {
byte[] encrypted = null;
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
encrypted = cipher.doFinal(data);
} catch (NoSuchAlgorithmException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
} catch (NoSuchPaddingException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
} catch (BadPaddingException e) {
// should not happen
e.printStackTrace();
System.exit(-1);
}
return encrypted;
}
/**
* Dump Byte Array.
*
* @param dump byte array.
*/
private static void hexDump(byte[] dump) {
HexDumpEncoder hexDump = new HexDumpEncoder();
System.out.println(hexDump.encode(dump));
}
}
実行結果 †
PUBLIC KEY (RSA X.509)
0000: 30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 0..0...*.H......
0010: 05 00 03 81 8D 00 30 81 89 02 81 81 00 B3 A7 70 ......0........p
0020: 33 E6 77 02 13 5B AE E5 C6 97 A0 95 8B 4F B9 11 3.w..[.......O..
0030: FE 54 22 97 9F 94 AD ED CB 7D 85 C5 40 88 46 FF .T".........@.F.
0040: 59 B8 AF 69 5F AC 06 67 F9 F0 6D 4D EE 2A 25 71 Y..i_..g..mM.*%q
0050: 90 96 B2 50 1E 23 71 22 56 C9 7B 0D 04 29 44 AD ...P.#q"V....)D.
0060: 62 DF ED 08 D6 64 24 C6 E0 B0 ED D8 AA 8C DA A0 b....d$.........
0070: C0 23 83 20 4E A4 8F 33 AB EF 0E 9B 2F CA AA B2 .#. N..3..../...
0080: 7C 96 13 10 F2 16 5B D7 D2 48 42 8D 0F 7A 5B AC ......[..HB..z[.
0090: B9 71 49 55 81 03 B4 9B 82 68 95 83 A3 02 03 01 .qIU.....h......
00A0: 00 01
PRIVATE KEY (RSA PKCS#8)
0000: 30 82 02 77 02 01 00 30 0D 06 09 2A 86 48 86 F7 0..w...0...*.H..
0010: 0D 01 01 01 05 00 04 82 02 61 30 82 02 5D 02 01 .........a0..]..
0020: 00 02 81 81 00 B3 A7 70 33 E6 77 02 13 5B AE E5 .......p3.w..[..
0030: C6 97 A0 95 8B 4F B9 11 FE 54 22 97 9F 94 AD ED .....O...T".....
0040: CB 7D 85 C5 40 88 46 FF 59 B8 AF 69 5F AC 06 67 ....@.F.Y..i_..g
0050: F9 F0 6D 4D EE 2A 25 71 90 96 B2 50 1E 23 71 22 ..mM.*%q...P.#q"
0060: 56 C9 7B 0D 04 29 44 AD 62 DF ED 08 D6 64 24 C6 V....)D.b....d$.
0070: E0 B0 ED D8 AA 8C DA A0 C0 23 83 20 4E A4 8F 33 .........#. N..3
0080: AB EF 0E 9B 2F CA AA B2 7C 96 13 10 F2 16 5B D7 ..../.........[.
0090: D2 48 42 8D 0F 7A 5B AC B9 71 49 55 81 03 B4 9B .HB..z[..qIU....
00A0: 82 68 95 83 A3 02 03 01 00 01 02 81 80 53 23 C4 .h...........S#.
00B0: B8 30 0A 99 2A 4E 3E A5 55 7F 6C 30 68 B5 2F 47 .0..*N>.U.l0h./G
00C0: 95 74 68 41 D4 F7 20 7A B0 B6 59 46 CC B3 84 6F .thA.. z..YF...o
00D0: BD 9C CB 88 AF 5E D3 E4 20 75 D4 8F C1 0D 3E 20 .....^.. u....>
00E0: CD 32 00 39 35 89 5F 5C ED DE F6 14 32 37 2D B6 .2.95._\....27-.
00F0: 5D EE 44 7A 3E E4 B3 8E 55 0A BB 1E 3B 69 E1 E7 ].Dz>...U...;i..
0100: FF 37 CA 0F 54 0A 3B A8 A0 48 8B 40 0E 78 DC 61 .7..T.;..H.@.x.a
0110: 92 62 88 AC 68 C9 7B 8D 8F 0E F7 24 FA B2 C6 C3 .b..h......$....
0120: 37 37 72 EC 6A EF 5A AD B1 F3 B5 0D 51 02 41 00 77r.j.Z.....Q.A.
0130: DE 0F 9F 50 A8 BA 84 00 72 89 33 CF 93 29 97 A5 ...P....r.3..)..
0140: 4D 23 4C 54 68 EF DA 77 50 E9 F1 DB C7 0F 51 DB M#LTh..wP.....Q.
0150: BE 2A 95 BE 81 09 25 DF C1 CD 26 D2 F1 4F 38 05 .*....%...&..O8.
0160: 0E 1B C6 1C D5 2A F1 CE 25 92 40 4E 31 DB CD 0B .....*..%.@N1...
0170: 02 41 00 CF 1C 98 F3 39 65 9D 6D D1 A5 AD 83 E2 .A.....9e.m.....
0180: 84 FF CB 51 A6 6A 5D A2 70 D7 89 4D D2 EE 66 E6 ...Q.j].p..M..f.
0190: 00 B7 5F 78 4A 4E A3 4A 50 FD 6F 50 8F E1 95 F3 .._xJN.JP.oP....
01A0: C7 3A CA 8F E4 1D B2 45 8C 8D 0F 45 4C EE 5A DE .:.....E...EL.Z.
01B0: 7C 52 C9 02 40 42 E1 DB AF 34 92 B0 CD 5D B1 FB .R..@B...4...]..
01C0: 5B EA CC 1D 33 99 6F 27 3F 49 37 EC CA 01 21 E5 [...3.o'?I7...!.
01D0: 49 B7 C3 E2 78 D7 E7 05 A1 12 46 4A 15 01 CF 23 I...x.....FJ...#
01E0: 81 67 52 DF E1 8D E5 49 9F 47 89 1E B9 63 51 90 .gR....I.G...cQ.
01F0: 72 BC CB A2 0F 02 41 00 C4 4F 5F EE 52 FE 2D 1D r.....A..O_.R.-.
0200: 55 B5 0B 65 D1 C4 AC CC 64 05 30 16 B6 8C EC CF U..e....d.0.....
0210: 79 53 B0 A3 19 E9 9D E6 41 17 75 B8 33 0D D7 5A yS......A.u.3..Z
0220: B6 6A DA B1 0E 93 4D F7 88 31 F9 AF EB 5A 50 AE .j....M..1...ZP.
0230: 23 CA CA B6 98 E2 10 79 02 41 00 A1 15 83 7A 5B #......y.A....z[
0240: D9 A7 66 49 E0 72 C3 CC 82 8C EC CD D4 E9 0C 91 ..fI.r..........
0250: DE F1 AC 50 39 DB FC FC 65 F8 96 86 20 43 22 9F ...P9...e... C".
0260: 6C 1B 49 08 61 25 5E D8 EE F6 C9 45 8D D8 7C 84 l.I.a%^....E....
0270: 01 5C 8A D5 F1 1B 64 42 75 C8 7C
Private Key: 1024bit.
Public Key: 1024bit.
RAW DATA
0000: 49 6E 73 61 6E 69 74 79 3A 20 64 6F 69 6E 67 20 Insanity: doing
0010: 74 68 65 20 73 61 6D 65 20 74 68 69 6E 67 20 6F the same thing o
0020: 76 65 72 20 61 6E 64 20 6F 76 65 72 20 61 67 61 ver and over aga
0030: 69 6E 20 61 6E 64 20 65 78 70 65 63 74 69 6E 67 in and expecting
0040: 20 64 69 66 66 65 72 65 6E 74 20 72 65 73 75 6C different resul
0050: 74 73 2E 41 6C 62 65 72 74 20 45 69 6E 73 74 65 ts.Albert Einste
0060: 69 6E
ENCRYPTED DATA
0000: 26 30 89 62 52 AC 90 6F 1B 7C 87 06 B2 72 AE 85 &0.bR..o.....r..
0010: DC 40 D0 40 5F B5 47 54 59 D2 6E 40 C0 B3 5D B9 .@.@_.GTY.n@..].
0020: FE E1 F2 20 53 A9 36 C6 5F 7A FA 31 78 5D 29 79 ... S.6._z.1x])y
0030: 93 5F 1D BB 23 10 FA F0 53 B2 38 A4 C2 6D 6A D0 ._..#...S.8..mj.
0040: C6 C8 D6 F0 08 24 EB 52 2B 43 23 18 C3 17 F8 A8 .....$.R+C#.....
0050: 3B 2E F7 D1 90 A4 11 0B A5 43 49 BA 6E 9C 94 AA ;........CI.n...
0060: B0 3C EC B4 95 BB 67 9C 48 DB D1 83 CC 83 56 41 .<....g.H.....VA
0070: AF B5 65 31 2A 07 79 AB 1F 7E 03 3B C7 A9 95 2A ..e1*.y....;...*
DECRYPTED DATA
0000: 49 6E 73 61 6E 69 74 79 3A 20 64 6F 69 6E 67 20 Insanity: doing
0010: 74 68 65 20 73 61 6D 65 20 74 68 69 6E 67 20 6F the same thing o
0020: 76 65 72 20 61 6E 64 20 6F 76 65 72 20 61 67 61 ver and over aga
0030: 69 6E 20 61 6E 64 20 65 78 70 65 63 74 69 6E 67 in and expecting
0040: 20 64 69 66 66 65 72 65 6E 74 20 72 65 73 75 6C different resul
0050: 74 73 2E 41 6C 62 65 72 74 20 45 69 6E 73 74 65 ts.Albert Einste
0060: 69 6E
平文が鍵長よりも長いとき †
鍵長が 1024bit のときには、117byte までの平文しか暗号化できません。(cf.RSA-???? の鍵長)
…
Private Key: 1024bit.
Public Key: 1024bit.
RAW DATA
0000: 49 6E 73 61 6E 69 74 79 3A 20 64 6F 69 6E 67 20 Insanity: doing
0010: 74 68 65 20 73 61 6D 65 20 74 68 69 6E 67 20 6F the same thing o
0020: 76 65 72 20 61 6E 64 20 6F 76 65 72 20 61 67 61 ver and over aga
0030: 69 6E 20 61 6E 64 20 65 78 70 65 63 74 69 6E 67 in and expecting
0040: 20 64 69 66 66 65 72 65 6E 74 20 72 65 73 75 6C different resul
0050: 74 73 2E 41 6C 62 65 72 74 20 45 69 6E 73 74 65 ts.Albert Einste
0060: 69 6E 48 61 70 70 69 6E 65 73 73 20 69 73 20 6E inHappiness is n
0070: 6F 74 68 69 6E 67 20 6D 6F 72 65 20 74 68 61 6E othing more than
0080: 20 67 6F 6F 64 20 68 65 61 6C 74 68 20 61 6E 64 good health and
0090: 20 61 20 62 61 64 20 6D 65 6D 6F 72 79 2E 41 6C a bad memory.Al
00A0: 62 65 72 74 20 53 63 68 77 65 69 74 7A 65 72
javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes
at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at com.snail.example.RSAExam.encrypt(RSAExam.java:165)
at com.snail.example.RSAExam.main(RSAExam.java:64)
Open SSL で作った鍵ペアを使う †
秘密鍵(PKCS#8)と公開鍵(X.509)を作る †
- 申請書の作成
kagyuu@grape:~> /usr/share/ssl/misc/CA.pl -newreq-nodes
Generating a 1024 bit RSA private key
..++++++
....++++++
writing new private key to 'newreq.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Musashi
Locality Name (eg, city) []:Edo
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ISEYA LTD
Organizational Unit Name (eg, section) []:Web Admin
Common Name (eg, YOUR name) []:Saemon
Email Address []:saemon@ise.co.jp
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Request (and private key) is in newreq.pem
- 申請書から秘密鍵を取り出す
kagyuu@grape:~> openssl rsa -in newreq.pem -out key.prv
writing RSA key
kagyuu@grape:~> openssl pkcs8 -topk8 -in key.prv -out key.pkcs8 -nocrypt
kagyuu@grape:~> cat key.pkcs8
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANlpV2MggGPPSBMU
Ht0myHcLCS1PfJ+Iqrn8+6a/uq1//X8Z/a+/64RoOPAowL2z3XTp1ylj9KGh9uIv
QIZzcRtHF8tVubY3np9mN5htWzHlDStF7YTb0ypJlpKD9Oon9LhlXxN1hMe9HTuA
AlH67SAUJYk6n03cRzE7ZO2VqjQrAgMBAAECgYABOxJukjmH1x2OVhfSoqyR1/Mm
WYPYF1r4EJGQIRe6cbYKqSgBfbGknz5rRZ/JsyH2zngUWOeCnrsaDrBr0m16emCZ
8M+MEd6XxdtXH0WMKstMA9ZQLWkLKkugljOT73Ud1CVTO7eo2HOixU3m5qei0gte
NtgOrt3M+Zw2KbYxuQJBAPoKg76m0hAW3FzUD5+MBZS54BJpFADpvlY9Gb9c8oY7
dfruo5isqlo+JCQoft1v9iX0RZV4z8c9yX6Gb/jA7T0CQQDel8FwySQKF4jDnjOC
Il0R5xdbT/0fEm0YwQ6fN/WJiXM6B/s4AHAc2Lo/GHm3rzUw/ra7u91bxpT++6Db
dQ2HAkEAsN81OGzbFWSGdufPMWYkIIOnnH5WFxtBd9F64CIIsKlpGJssgHhLfNCO
UkGPFGb5sPltK4GtQNxVJzpEBKu8ZQJAClGCmBXa49TfdCH7RUcOhWvu+z6j/zK9
d+5LHTpc2XlTrBb+oEP07oFlcNNToR4wGwtTsTQuOLjl40QK2uF8NQJAN++aX5bf
xhPw7fu7KbSc6pvoj8NS7hE7WD911tkBnR2ooGH8of3N3rq0qEzB6t7d1HOfNXmN
gR95xd2jgU9NJw==
-----END PRIVATE KEY-----
kagyuu@grape:~>
"-nocrypt"にしないと、Java(PKCS8EncodedKeySpec?)から読めないようだ
- 申請書から公開鍵を取り出す
kagyuu@grape:~> openssl rsa -in newreq.pem -pubout -out key.pub.x509
writing RSA key
kagyuu@grape:~> cat key.pub.x509
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZaVdjIIBjz0gTFB7dJsh3Cwkt
T3yfiKq5/Pumv7qtf/1/Gf2vv+uEaDjwKMC9s9106dcpY/ShofbiL0CGc3EbRxfL
Vbm2N56fZjeYbVsx5Q0rRe2E29MqSZaSg/TqJ/S4ZV8TdYTHvR07gAJR+u0gFCWJ
Op9N3EcxO2Ttlao0KwIDAQAB
-----END PUBLIC KEY-----
- (補足) CAによって署名された鍵は、現状(Java6)の KeyFacotory? ではうまく読み込めないようだ
- CA署名済みの公開鍵を食わせると、keySpecを作るまではうまくいくが、KeyFactory?がうまく動かない
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(readPEM(fileName)); // 署名済み公開鍵読み込み
PublicKey key = KeyFactory.getInstance("DSA").generatePublic(keySpec);
- 今回やったように、署名していない公開鍵を食わせるとうまくいく
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(readPEM(fileName)); // 署名していない公開鍵読み込み
PublicKey key = KeyFactory.getInstance("RSA").generatePublic(keySpec);
- 今回の実習をするに当たり、当初はCA署名済みの公開鍵を使おうと思っていたので、鍵セットを「申請書」の形で作った。単に鍵セットを作るだけなら以下のコマンドでもOK
> openssl genrsa -out newreq.pem 1024
Java SEで、鍵セットを読み取る †
- KeyPairGenerator? で鍵セットを作る代わりに、open ssl で作成した鍵セットを読み込む以下の PemUtil? を使う。
- 鍵の格納形式は PEM 形式を想定しています。
- "----BEGIN ????-----"と"----END ????-----"の間に、Base64でエンコード(ASCII文字列化)された鍵が格納されているので、MimeUtility?.decode() でバイナリに戻してやります。
- DER形式ならば、そのまま読み込めば良いんだけど、ファイルとしての扱いが楽なので普通はPEM形式を使うでしょう
- MimeUtility?は、JavaMail?の構成品です
- ソースコード
package com.snail.example;
import sun.misc.HexDumpEncoder;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.mail.MessagingException;
import javax.mail.internet.MimeUtility;
/**
* Read PEM Formatted RSA Keys
*
* @author kagyuu
* @version $Revision$
*/
public class PemUtil {
/**
* Read RSA Private Key
* @param fileName file name of private key file
* @return RSA Private Key
* @throws Exception something wrong
*/
public static PublicKey readRSAPrivateKey(String fileName)
throws Exception {
try {
return KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(readPEM(fileName)));
} catch (InvalidKeySpecException e) {
throw new Exception("Readed Key is invalid.", e);
} catch (NoSuchAlgorithmException e) {
throw new Exception("RSA is wrong algorithm name.", e);
}
}
/**
* Read RSA Public Key
* @param fileName file name of public key file
* @return RSA Public Key
* @throws Exception something wrong
*/
public static PrivateKey readRSAPublicKey(String fileName)
throws Exception {
try {
return KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(readPEM(
fileName)));
} catch (InvalidKeySpecException e) {
throw new Exception("Readed Key is invalid.", e);
} catch (NoSuchAlgorithmException e) {
throw new Exception("RSA is wrong algorithm name.", e);
}
}
/**
* Decode Base 64 String to Binary Data.
* @param pem Base 64 String
* @return Binary Data
* @throws Exception pem is wrong data or can't read pem.
*/
private static byte[] decodeBase64(String pem) throws Exception {
System.out.println(pem);
InputStream in;
try {
in = MimeUtility.decode(new ByteArrayInputStream(pem.getBytes()), "base64");
byte[] buf = new byte[in.available()];
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
HexDumpEncoder hexDump = new HexDumpEncoder();
System.out.println(hexDump.encode(out.toByteArray()));
return out.toByteArray();
} catch (MessagingException e) {
throw new Exception("the PEM String is not Base64 Format.", e);
} catch (IOException e) {
throw new Exception("Can't read the PEM String.", e);
}
}
/**
* read PEM file.
* @param fileName file pem file
* @return the contents of file name
* @throws Exception something wrong
*/
private static byte[] readPEM(String fileName) throws Exception {
System.out.println("\n" + fileName);
BufferedReader br;
try {
br = new BufferedReader(new FileReader(new File(fileName)));
String line;
StringBuilder sb = new StringBuilder();
boolean isContents = false;
while ((line = br.readLine()) != null) {
if (line.matches("[-]+BEGIN[ A-Z]+[-]+")) {
isContents = true;
} else if (line.matches("[-]+END[ A-Z]+[-]+")) {
isContents = false;
} else if (isContents) {
sb.append(line);
sb.append("\n");
}
}
return decodeBase64(sb.toString());
} catch (FileNotFoundException e) {
throw new Exception("File not found.", e);
} catch (IOException e) {
throw new Exception("can't read the PEM file.", e);
}
}
}
実行結果 †
- RSAExam#main() の引数に公開鍵と秘密鍵のファイル名を指定した場合には PEMUtil を使ってそれらを読み取るように改造して実行する
public class RSAExam {
・・・(中略)・・・
/**
* Main Routine.
*
* @param args Commandline Argument
*/
public static void main(String[] args) {
try {
// Create Key Pair
KeyPair keyPair = null;
if (args.length > 0) {
keyPair = readKeyPair(args);
} else {
keyPair = createKeyPair();
}
System.out.println("Private Key: "
+ ((RSAKey) keyPair.getPrivate()).getModulus().bitLength() + "bit.");
System.out.println("Public Key: "
+ ((RSAKey) keyPair.getPublic()).getModulus().bitLength() + "bit.");
// Raw data
System.out.println("\nRAW DATA");
byte[] rawText = EXAMPLE.getBytes();
hexDump(rawText);
// Encrypt data
byte[] encryptedText = encrypt(keyPair.getPublic(), rawText);
System.out.println("\nENCRYPTED DATA");
hexDump(encryptedText);
// Decrypt data
byte[] decryptedText = decrypt(keyPair.getPrivate(), encryptedText);
System.out.println("\nDECRYPTED DATA");
hexDump(decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
・・・(中略)・・・
/**
* Read Key Pairs.
* @param args
* [0]:the name of the private key file
* [1]:the name of the public key file
* @return Key Pair
* @throws Exception something wrong
*/
private static KeyPair readKeyPair(String[] args) throws Exception {
PublicKey publicKey = PemUtil.readRSAPrivateKey(args[0]);
PrivateKey privateKey = PemUtil.readRSAPublicKey(args[1]);
return new KeyPair(publicKey, privateKey);
}
}
- 実行結果
key.pub.x509
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZaVdjIIBjz0gTFB7dJsh3Cwkt
T3yfiKq5/Pumv7qtf/1/Gf2vv+uEaDjwKMC9s9106dcpY/ShofbiL0CGc3EbRxfL
Vbm2N56fZjeYbVsx5Q0rRe2E29MqSZaSg/TqJ/S4ZV8TdYTHvR07gAJR+u0gFCWJ
Op9N3EcxO2Ttlao0KwIDAQAB
0000: 30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 0..0...*.H......
0010: 05 00 03 81 8D 00 30 81 89 02 81 81 00 D9 69 57 ......0.......iW
0020: 63 20 80 63 CF 48 13 14 1E DD 26 C8 77 0B 09 2D c .c.H....&.w..-
0030: 4F 7C 9F 88 AA B9 FC FB A6 BF BA AD 7F FD 7F 19 O...............
0040: FD AF BF EB 84 68 38 F0 28 C0 BD B3 DD 74 E9 D7 .....h8.(....t..
0050: 29 63 F4 A1 A1 F6 E2 2F 40 86 73 71 1B 47 17 CB )c...../@.sq.G..
0060: 55 B9 B6 37 9E 9F 66 37 98 6D 5B 31 E5 0D 2B 45 U..7..f7.m[1..+E
0070: ED 84 DB D3 2A 49 96 92 83 F4 EA 27 F4 B8 65 5F ....*I.....'..e_
0080: 13 75 84 C7 BD 1D 3B 80 02 51 FA ED 20 14 25 89 .u....;..Q.. .%.
0090: 3A 9F 4D DC 47 31 3B 64 ED 95 AA 34 2B 02 03 01 :.M.G1;d...4+...
00A0: 00 01
key.pkcs8
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANlpV2MggGPPSBMU
Ht0myHcLCS1PfJ+Iqrn8+6a/uq1//X8Z/a+/64RoOPAowL2z3XTp1ylj9KGh9uIv
QIZzcRtHF8tVubY3np9mN5htWzHlDStF7YTb0ypJlpKD9Oon9LhlXxN1hMe9HTuA
AlH67SAUJYk6n03cRzE7ZO2VqjQrAgMBAAECgYABOxJukjmH1x2OVhfSoqyR1/Mm
WYPYF1r4EJGQIRe6cbYKqSgBfbGknz5rRZ/JsyH2zngUWOeCnrsaDrBr0m16emCZ
8M+MEd6XxdtXH0WMKstMA9ZQLWkLKkugljOT73Ud1CVTO7eo2HOixU3m5qei0gte
NtgOrt3M+Zw2KbYxuQJBAPoKg76m0hAW3FzUD5+MBZS54BJpFADpvlY9Gb9c8oY7
dfruo5isqlo+JCQoft1v9iX0RZV4z8c9yX6Gb/jA7T0CQQDel8FwySQKF4jDnjOC
Il0R5xdbT/0fEm0YwQ6fN/WJiXM6B/s4AHAc2Lo/GHm3rzUw/ra7u91bxpT++6Db
dQ2HAkEAsN81OGzbFWSGdufPMWYkIIOnnH5WFxtBd9F64CIIsKlpGJssgHhLfNCO
UkGPFGb5sPltK4GtQNxVJzpEBKu8ZQJAClGCmBXa49TfdCH7RUcOhWvu+z6j/zK9
d+5LHTpc2XlTrBb+oEP07oFlcNNToR4wGwtTsTQuOLjl40QK2uF8NQJAN++aX5bf
xhPw7fu7KbSc6pvoj8NS7hE7WD911tkBnR2ooGH8of3N3rq0qEzB6t7d1HOfNXmN
gR95xd2jgU9NJw==
0000: 30 82 02 76 02 01 00 30 0D 06 09 2A 86 48 86 F7 0..v...0...*.H..
0010: 0D 01 01 01 05 00 04 82 02 60 30 82 02 5C 02 01 .........`0..\..
0020: 00 02 81 81 00 D9 69 57 63 20 80 63 CF 48 13 14 ......iWc .c.H..
0030: 1E DD 26 C8 77 0B 09 2D 4F 7C 9F 88 AA B9 FC FB ..&.w..-O.......
0040: A6 BF BA AD 7F FD 7F 19 FD AF BF EB 84 68 38 F0 .............h8.
0050: 28 C0 BD B3 DD 74 E9 D7 29 63 F4 A1 A1 F6 E2 2F (....t..)c...../
0060: 40 86 73 71 1B 47 17 CB 55 B9 B6 37 9E 9F 66 37 @.sq.G..U..7..f7
0070: 98 6D 5B 31 E5 0D 2B 45 ED 84 DB D3 2A 49 96 92 .m[1..+E....*I..
0080: 83 F4 EA 27 F4 B8 65 5F 13 75 84 C7 BD 1D 3B 80 ...'..e_.u....;.
0090: 02 51 FA ED 20 14 25 89 3A 9F 4D DC 47 31 3B 64 .Q.. .%.:.M.G1;d
00A0: ED 95 AA 34 2B 02 03 01 00 01 02 81 80 01 3B 12 ...4+.........;.
00B0: 6E 92 39 87 D7 1D 8E 56 17 D2 A2 AC 91 D7 F3 26 n.9....V.......&
00C0: 59 83 D8 17 5A F8 10 91 90 21 17 BA 71 B6 0A A9 Y...Z....!..q...
00D0: 28 01 7D B1 A4 9F 3E 6B 45 9F C9 B3 21 F6 CE 78 (.....>kE...!..x
00E0: 14 58 E7 82 9E BB 1A 0E B0 6B D2 6D 7A 7A 60 99 .X.......k.mzz`.
00F0: F0 CF 8C 11 DE 97 C5 DB 57 1F 45 8C 2A CB 4C 03 ........W.E.*.L.
0100: D6 50 2D 69 0B 2A 4B A0 96 33 93 EF 75 1D D4 25 .P-i.*K..3..u..%
0110: 53 3B B7 A8 D8 73 A2 C5 4D E6 E6 A7 A2 D2 0B 5E S;...s..M......^
0120: 36 D8 0E AE DD CC F9 9C 36 29 B6 31 B9 02 41 00 6.......6).1..A.
0130: FA 0A 83 BE A6 D2 10 16 DC 5C D4 0F 9F 8C 05 94 .........\......
0140: B9 E0 12 69 14 00 E9 BE 56 3D 19 BF 5C F2 86 3B ...i....V=..\..;
0150: 75 FA EE A3 98 AC AA 5A 3E 24 24 28 7E DD 6F F6 u......Z>$$(..o.
0160: 25 F4 45 95 78 CF C7 3D C9 7E 86 6F F8 C0 ED 3D %.E.x..=...o...=
0170: 02 41 00 DE 97 C1 70 C9 24 0A 17 88 C3 9E 33 82 .A....p.$.....3.
0180: 22 5D 11 E7 17 5B 4F FD 1F 12 6D 18 C1 0E 9F 37 "]...[O...m....7
0190: F5 89 89 73 3A 07 FB 38 00 70 1C D8 BA 3F 18 79 ...s:..8.p...?.y
01A0: B7 AF 35 30 FE B6 BB BB DD 5B C6 94 FE FB A0 DB ..50.....[......
01B0: 75 0D 87 02 41 00 B0 DF 35 38 6C DB 15 64 86 76 u...A...58l..d.v
01C0: E7 CF 31 66 24 20 83 A7 9C 7E 56 17 1B 41 77 D1 ..1f$ ....V..Aw.
01D0: 7A E0 22 08 B0 A9 69 18 9B 2C 80 78 4B 7C D0 8E z."...i..,.xK...
01E0: 52 41 8F 14 66 F9 B0 F9 6D 2B 81 AD 40 DC 55 27 RA..f...m+..@.U'
01F0: 3A 44 04 AB BC 65 02 40 0A 51 82 98 15 DA E3 D4 :D...e.@.Q......
0200: DF 74 21 FB 45 47 0E 85 6B EE FB 3E A3 FF 32 BD .t!.EG..k..>..2.
0210: 77 EE 4B 1D 3A 5C D9 79 53 AC 16 FE A0 43 F4 EE w.K.:\.yS....C..
0220: 81 65 70 D3 53 A1 1E 30 1B 0B 53 B1 34 2E 38 B8 .ep.S..0..S.4.8.
0230: E5 E3 44 0A DA E1 7C 35 02 40 37 EF 9A 5F 96 DF ..D....5.@7.._..
0240: C6 13 F0 ED FB BB 29 B4 9C EA 9B E8 8F C3 52 EE ......).......R.
0250: 11 3B 58 3F 75 D6 D9 01 9D 1D A8 A0 61 FC A1 FD .;X?u.......a...
0260: CD DE BA B4 A8 4C C1 EA DE DD D4 73 9F 35 79 8D .....L.....s.5y.
0270: 81 1F 79 C5 DD A3 81 4F 4D 27
Private Key: 1024bit.
Public Key: 1024bit.
RAW DATA
0000: 49 6E 73 61 6E 69 74 79 3A 20 64 6F 69 6E 67 20 Insanity: doing
0010: 74 68 65 20 73 61 6D 65 20 74 68 69 6E 67 20 6F the same thing o
0020: 76 65 72 20 61 6E 64 20 6F 76 65 72 20 61 67 61 ver and over aga
0030: 69 6E 20 61 6E 64 20 65 78 70 65 63 74 69 6E 67 in and expecting
0040: 20 64 69 66 66 65 72 65 6E 74 20 72 65 73 75 6C different resul
0050: 74 73 2E 41 6C 62 65 72 74 20 45 69 6E 73 74 65 ts.Albert Einste
0060: 69 6E
ENCRYPTED DATA
0000: B7 55 98 4C B5 23 70 28 FC 6E 9F BE 1A 5B 18 BD .U.L.#p(.n...[..
0010: E8 0F 42 4A 17 28 A0 52 27 50 1B 2D 5E C7 67 BC ..BJ.(.R'P.-^.g.
0020: 32 33 48 0A 69 EF 3C DA 92 F3 2D 3C 2C DE 29 8D 23H.i.<...-<,.).
0030: 47 8A 1A 4B 69 6E 7D 1F F5 EF 61 EB F5 AA 17 F4 G..Kin....a.....
0040: 8A 69 29 6E C1 4A 4F 06 36 05 22 E2 B0 65 7B E9 .i)n.JO.6."..e..
0050: 55 87 95 9C D8 A6 01 7B 22 C4 48 3F 7E 34 D2 B5 U.......".H?.4..
0060: B4 E4 E9 23 58 C6 6A 85 06 9E 38 0F 94 E7 0D 5A ...#X.j...8....Z
0070: 2F 66 F0 DC E2 33 19 B8 74 02 31 37 18 F2 D1 AC /f...3..t.17....
DECRYPTED DATA
0000: 49 6E 73 61 6E 69 74 79 3A 20 64 6F 69 6E 67 20 Insanity: doing
0010: 74 68 65 20 73 61 6D 65 20 74 68 69 6E 67 20 6F the same thing o
0020: 76 65 72 20 61 6E 64 20 6F 76 65 72 20 61 67 61 ver and over aga
0030: 69 6E 20 61 6E 64 20 65 78 70 65 63 74 69 6E 67 in and expecting
0040: 20 64 69 66 66 65 72 65 6E 74 20 72 65 73 75 6C different resul
0050: 74 73 2E 41 6C 62 65 72 74 20 45 69 6E 73 74 65 ts.Albert Einste
0060: 69 6E
参考文献 †
- サルにもわかるRSA暗号, http://www.maitou.gr.jp/rsa/
- PHPマニュアル, http://jp2.php.net/manual/ja/function.openssl-public-encrypt.php#55901
Java#JavaSE