DotNet RSACryptoServiceProviderで作成した秘密鍵
のファイル(privateKey.xml)を読み込んで、希望のファイルを暗号化します。
ここよりダウンロードして実験できます。
(ソース:RsaSEncrypt.java)
なお、自身のprivateKey.xmlファイルが実行位置に存在しないと、実行できません。
また、暗号化に使う平文のサイズも128以内のサイズを指定ください。
(これは、下記のプログラム上の制約です。)
以下に実行例を示します。
Z:\security>java RsaSEncrypt ルート要素のタグ名:RSAKeyValue D= PQDJvs3JNOW7Cffe4HJrxyFWGjRNPfmYJxciKpcoa3B9wFiHLAyR+A2MwlDWSE58mgvDEp8ertwfv 4FeT27xnM1DsydFwZCZMsZTRYlfx+Cq3bTEnL4N6WdLG1p9ktPdbqq6jlQ3FQpJl38RDA8C5cuRekkZk NOMOyTlOGzJ8gE= Modulus= kUeqVlfMc3RsGBo0Q+voiNV9LoH9gmv8i7gobUNG5rIoNsIRU7GUJpU9qoX7htlpZROqvEA gR7GfFNbL+kf+Z0nnUXrixXv+9QPVGdNooeGvSqTx1tagnXUpZxJrk8ga1SMqsjaUX2hLPl80MCpZzTv 6YQ57Elb4C735/92VHHs= 暗号化するファイルを読み取ります。 privateKey.xmlで、 Z:\:\security\A_MD5.txtのファイルを暗号化し、 Z:\security\A_MD5.txt_private_encrypt.txt のファイル生成終了 Z:\security>
ここでは、次のMD5のハッシュ値のファイル(A_MD5.txt)を選択している例です。 以下がここで使ったA_MD5.txtの内容です。
2dffd34f9d51cc839696c265aef6b5d
上記実行で、次の『A_MD5.txt_private_encrypt.txt』の名前の暗号化された ファイルが作成されます。
dGtUFcsc97xRXJoJmtrrOVr2foKQm9z11MvrwM2s/pgkB+LgrawUM/6TpXyq5wG+09hNYDtXYfY7BWejNWBP+YaqElj5UwoVjFHuhPv5h8UkUCQFSjhkemzwovCEPyE0AUwcHcnXWWLt5ekwFoR2T3JA0oWGFv6vKvLm2j8rxtQ=
Javaで作成した復号プログラムを、
ここよりダウンロードして実験できます。
(ソース:RsaPDecrypt.java)
実行例を示します。
次のように実行します。まず、鍵を選択するダイアログが現れます。
それに対して、
暗号化で使った秘密キーと対になる公開鍵を選ばなければなりません。
以下では、『suzuki_publicKey.xml』のファイルを選んでいます。
次に上記で作成した『A_MD5.txt_private_encrypt.txt』を選択しています。
これによって出来上がる『A_MD5.txt_private_encrypt.txt_public_decrypt.txt』が
復号したファイルで、これは
『A_MD5.txt』と内容が一致するはずです。
Z:\security>java RsaPDecrypt 公開鍵のファイルを読み取ります。 ルート要素のタグ名:RSAKeyValue e= AQAB Modulus= kUeqVlfMc3RsGBo0Q+voiNV9LoH9gmv8i7gobUNG5rIoNsIRU7GUJpU9qoX7htlpZROqvEA gR7GfFNbL+kf+Z0nnUXrixXv+9QPVGdNooeGvSqTx1tagnXUpZxJrk8ga1SMqsjaUX2hLPl80MCpZzTv 6YQ57Elb4C735/92VHHs= 復号化するファイルを読み取ります。 復号対象:dGtUFcsc97xRXJoJmtrrOVr2foKQm9z11MvrwM2s/pgkB+LgrawUM/6TpXyq5wG+09hNYDt XYfY7BWejNWBP+YaqElj5UwoVjFHuhPv5h8UkUCQFSjhkemzwovCEPyE0AUwcHcnXWWLt5ekwFoR2T3J A0oWGFv6vKvLm2j8rxtQ= Z:\work1\suzuki_publicKey.xmlで、 Z:\work1\A_MD5.txt_private_encrypt.txtのファイルを復号し、 Z:\work1\A_MD5.txt_private_encrypt.txt_public_decrypt.txt のファイル生成終了 Z:\security>
以上で作成されたファイル「A_MD5.txt_private_encrypt.txt_public_decrypt.txt」の 内容を以下に示します。
2dffd34f9d51cc839696c265aef6b5d
import java.io.*;
import java.math.BigInteger;
import javax.swing.*;
//XMLファイルをパースしてDOMツリー取得に必要なインポート
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
//ドキュメントと要素操作に必要なインポート
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
// DotNet RSACryptoServiceProviderで作成した privateKey.xml の秘密鍵を読み取り
// その秘密鍵で、ダイアログで指定したファイルを暗号化し、「_private_encrypt.txt」を追加した名前で
// 保存する。なお保存は、バイナリをbase64で変換して行う。
public class RsaSEncrypt {
static BigInteger m;//Modulus 公開鍵
static BigInteger d;//D 秘密鍵
static final char[] B64 = { //変換に使うテーブル 64進(6bit分)を 16桁 4行で表現している
'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P',//00〜0Fの64進に対応する文字
'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,'Z' ,'a' ,'b' ,'c' ,'d' ,'e' ,'f',//10〜1Fの64進対応に対応する文字
'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o' ,'p' ,'q' ,'r' ,'s' ,'t' ,'u' ,'v',//20〜2Fの64進対応に対応する文字
'w' ,'x' ,'y' ,'z' ,'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'+' ,'/' //30〜3Fの64進対応に対応する文字
};
//引数のbyte配列を、Base64の文字列に変換して返す。
public static String encode64(byte a[]){
if (a.length == 0) return "";
StringBuffer s = new StringBuffer();//変換した文字列記憶用
int cnt3 = 0; //3yteカウント用
long data = 0; //変換対象用:3byteを設定し、4文字で取り出す
int idx = 0;
do{
//data に 3byte分を設定
data <<= 8;
if (idx < a.length){
if (a[idx] >= 0) {//Javaは符号なしがないので、if文で処理を変える
data += a[idx];
}else{
data += 256 + a[idx]; //符号なしのコードに変換して加算
}
}
cnt3++;
if (cnt3 == 3){//3byteごとに変換
//dataを4個の64進に対応する文字に変換
int i = (int)(data / (64 * 64 * 64));
//System.out.println(data + "," + i + "," + 256 * 256 * 256);
s.append(B64[i]);//1文字目
data = data % (64 * 64 * 64);
i = (int)(data / (64 * 64));
s.append(B64[i]);//2文字目
data = data % (64 * 64);
i = (int)(data / (64));
s.append(B64[i]);//3文字目
data = data % 64;
s.append(B64[(int)data]);//4文字目
data = 0; //次の変換データの準備
cnt3 = 0;
}
idx++;
} while (idx < a.length || cnt3 != 0);
int len = s.length(); //文字列の長さ
String rtnval = "";
if (a.length % 3 == 2){
return s.substring(0, len - 1) + "=";
}else if (a.length % 3 == 1){
return s.substring(0, len - 2) + "==";
}else{
return s.toString();
}
}
//Base64の文字列から、バイナリデータを求める。
public static byte[] decode64(String s){
int n = s.length() * 3 / 4;
if (s.endsWith("==")) n -= 2;
else if (s.endsWith("=")) n -= 1;
byte[] bi = new byte[n];
int iset = 0;
int len = s.length();
int data = 0;
int icount = 0;
int i;
try{
for (i = 0; i < len; i++){ //文字を順番に処理する。
char c = s.charAt(i);
data <<= 6;// 6ビットシフト
icount++;
if (c != '='){
//Base64の文字から、テーブル内のインデックスを求める。
if (c >= 'A' && c <= 'Z') {
data |= c - 'A';
}else if (c >= 'a' && c <= 'z'){
data |= c - 'a' + 0x1a;
}else if (c >= '0' && c <= '9'){
data |= c - '0' + 0x34;
}else if (c == '+'){
data |= 0x3e;
}else if (c == '/'){
data |= 0x3f;
}
}
if (icount == 4){
icount = 0;
bi[iset++] = (byte)((data >> 16) & 0x00ff);
bi[iset++] = (byte)((data >> 8) & 0x00ff);
bi[iset++] = (byte)(data & 0x00ff);
data = 0;
}
}
}
catch (ArrayIndexOutOfBoundsException e){ }
return bi;
}
// privateKey.xml のファイルを読み取り、mとdのクラス変数へ記憶
public static void loadPrivateKey(){
try {
//DOM オブジェクトツリーをパースするインスタンスを生成するDocumentBuilderオブジェクトを生成
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbfactory.newDocumentBuilder();
// パースを実行してDocumentオブジェクトを取得
Document document = builder.parse(new File("privateKey.xml"));
// ルート要素を取得
Element rootElement = document.getDocumentElement();
System.out.println("ルート要素のタグ名:" + rootElement.getTagName());
// nodeListの子孫となる "page" の名前の要素すべてを NodeListのインスタンスとして取得
NodeList nodeList = rootElement.getElementsByTagName("D");
String v = nodeList.item(0).getFirstChild().getNodeValue();
System.out.println("D= " + v);
d = new BigInteger(1,decode64(v));//秘密鍵
nodeList = rootElement.getElementsByTagName("Modulus");
v = nodeList.item(0).getFirstChild().getNodeValue();
System.out.println("Modulus= " + v);
m = new BigInteger(1,decode64(v));//公開鍵の一部
}
catch (Exception e){
System.out.println("privateKey.xmlのファイルが見つからない???。" + e.toString());
System.exit(0);
}
}
public static void main(String[] args) throws Exception{
loadPrivateKey(); //キー情報取得
System.out.println("暗号化するファイルを読み取ります。");
javax.swing.JFileChooser chooser = new javax.swing.JFileChooser(new File("."));
chooser.setDialogTitle("暗号化するファイルをファイル選択ください。");
System.out.println();
if (chooser.showOpenDialog(null) == JFileChooser.CANCEL_OPTION)
System.exit(0);
String srcFile = chooser.getSelectedFile().getPath();//keyファイルパス
File file = new File(srcFile);
int size = (int)file.length();
byte bi[] = new byte[size];//ファイルサイズのbyte配列を用意。
FileInputStream is = new FileInputStream(srcFile);
is.read(bi);//ファイルバイナリーを一括読み取る。
is.close(); //ファイルを閉じる。
BigInteger src = new BigInteger(1,bi);//平文
BigInteger encrypt = src.modPow(d, m); //暗号化
String keyBsae64 = encode64(encrypt.toByteArray());
FileOutputStream out = new FileOutputStream(srcFile + "_private_encrypt.txt");
out.write(keyBsae64.getBytes());
out.close();
System.out.println("privateKey.xmlで、\n"
+ srcFile + "のファイルを暗号化し、\n"
+ srcFile + "_private_encrypt.txt のファイル生成終了");
}
}
import java.io.*;
import java.math.BigInteger;
import javax.swing.*;
//XMLファイルをパースしてDOMツリー取得に必要なインポート
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
//ドキュメントと要素操作に必要なインポート
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
// DotNet RSACryptoServiceProviderで作成した xx_p_publicKey.xml の公開鍵を読み取り
// その公開鍵で、ダイアログで指定したファイルを復号化し、「_public_decrypt.txt」を追加した名前で
// 保存する。
public class RsaPDecrypt {
static BigInteger m;//Modulus 公開鍵
static BigInteger e;//公開鍵 PUBLIC_EXPONENT=<Exponent>
static final char[] B64 = { //変換に使うテーブル 64進(6bit分)を 16桁 4行で表現している
'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P',//00〜0Fの64進に対応する文字
'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,'Z' ,'a' ,'b' ,'c' ,'d' ,'e' ,'f',//10〜1Fの64進対応に対応する文字
'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o' ,'p' ,'q' ,'r' ,'s' ,'t' ,'u' ,'v',//20〜2Fの64進対応に対応する文字
'w' ,'x' ,'y' ,'z' ,'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'+' ,'/' //30〜3Fの64進対応に対応する文字
};
//引数のbyte配列を、Base64の文字列に変換して返す。
public static String encode64(byte a[]) {
if (a.length == 0) return "";
StringBuffer s = new StringBuffer();//変換した文字列記憶用
int cnt3 = 0; //3yteカウント用
long data = 0; //変換対象用:3byteを設定し、4文字で取り出す
int idx = 0;
do {
//data に 3byte分を設定
data <<= 8;
if (idx < a.length){
if (a[idx] >= 0){//Javaは符号なしがないので、if文で処理を変える
data += a[idx];
}else{
data += 256 + a[idx]; //符号なしのコードに変換して加算
}
}
cnt3++;
if (cnt3 == 3){//3byteごとに変換
//dataを4個の64進に対応する文字に変換
int i = (int)(data / (64 * 64 * 64));
//System.out.println(data + "," + i + "," + 256 * 256 * 256);
s.append(B64[i]);//1文字目
data = data % (64 * 64 * 64);
i = (int)(data / (64 * 64));
s.append(B64[i]);//2文字目
data = data % (64 * 64);
i = (int)(data / (64));
s.append(B64[i]);//3文字目
data = data % 64;
s.append(B64[(int)data]);//4文字目
data = 0; //次の変換データの準備
cnt3 = 0;
}
idx++;
} while (idx < a.length || cnt3 != 0);
int len = s.length(); //文字列の長さ
String rtnval = "";
if (a.length % 3 == 2){
return s.substring(0, len - 1) + "=";
}else if (a.length % 3 == 1){
return s.substring(0, len - 2) + "==";
}else{
return s.toString();
}
}
//Base64の文字列から、バイナリデータを求める。
public static byte[] decode64(String s){
int n = s.length() * 3 / 4;
if (s.endsWith("==")) n -= 2;
else if (s.endsWith("=")) n -= 1;
byte[] bi = new byte[n];
int iset = 0;
int len = s.length();
int data = 0;
int icount = 0;
int i;
try {
for (i = 0; i < len; i++){ //文字を順番に処理する。
char c = s.charAt(i);
data <<= 6;// 6ビットシフト
icount++;
if (c != '='){
//Base64の文字から、テーブル内のインデックスを求める。
if (c >= 'A' && c <= 'Z') {
data |= c - 'A';
}else if (c >= 'a' && c <= 'z'){
data |= c - 'a' + 0x1a;
}else if (c >= '0' && c <= '9'){
data |= c - '0' + 0x34;
}else if (c == '+'){
data |= 0x3e;
}else if (c == '/'){
data |= 0x3f;
}
}
if (icount == 4){
icount = 0;
bi[iset++] = (byte)((data >> 16) & 0x00ff);
bi[iset++] = (byte)((data >> 8) & 0x00ff);
bi[iset++] = (byte)(data & 0x00ff);
data = 0;
}
}
}
catch (ArrayIndexOutOfBoundsException e){ }
return bi;
}
// key のファイルを読み取り、公開鍵(eとdのクラス変数)へ記憶
public static void loadPublicKey(File key){
try {
//DOM オブジェクトツリーをパースするインスタンスを生成するDocumentBuilderオブジェクトを生成
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbfactory.newDocumentBuilder();
// パースを実行してDocumentオブジェクトを取得
Document document = builder.parse(key);
// ルート要素を取得
Element rootElement = document.getDocumentElement();
System.out.println("ルート要素のタグ名:" + rootElement.getTagName());
// nodeListの子孫となる "page" の名前の要素すべてを NodeListのインスタンスとして取得
NodeList nodeList = rootElement.getElementsByTagName("Exponent");
String v = nodeList.item(0).getFirstChild().getNodeValue();
System.out.println("e= " + v);
e = new BigInteger(1,decode64(v));//公開鍵の一部
nodeList = rootElement.getElementsByTagName("Modulus");
v = nodeList.item(0).getFirstChild().getNodeValue();
System.out.println("Modulus= " + v);
m = new BigInteger(1,decode64(v));//公開鍵の一部
}
catch (Exception e){
System.out.println(e.toString());
}
}
public static void main(String[] args) throws Exception{
System.out.println("公開鍵のファイルを読み取ります。");
javax.swing.JFileChooser chooser = new javax.swing.JFileChooser(new File("."));
chooser.setDialogTitle("公開鍵のxmlファイルをファイル選択ください。");
System.out.println();
if (chooser.showOpenDialog(null) == JFileChooser.CANCEL_OPTION)
System.exit(0);
String keyfile = chooser.getSelectedFile().getPath();//keyファイルパス
loadPublicKey(new File(keyfile)); //公開鍵の情報取得
System.out.println("復号化するファイルを読み取ります。");
javax.swing.JFileChooser chooser2 = new javax.swing.JFileChooser(new File("."));
chooser2.setDialogTitle("復号化するファイルをファイル選択ください。");
System.out.println();
if (chooser2.showOpenDialog(null) == JFileChooser.CANCEL_OPTION)
System.exit(0);
String srcFile = chooser2.getSelectedFile().getPath();//keyファイルパス
File file = new File(srcFile);
int size = (int)file.length();
byte b64[] = new byte[size];//ファイルサイズのbyte配列を用意。
FileInputStream is = new FileInputStream(srcFile);
is.read(b64);//base64ファイルを一括読み取る。
is.close(); //ファイルを閉じる。
String s64 = new String(b64);
System.out.println("復号対象:" + s64);
byte bi[] = decode64(s64);
BigInteger src = new BigInteger(1,bi);//暗号文
BigInteger encrypt = src.modPow(e, m); //復号化
FileOutputStream out = new FileOutputStream(srcFile + "_public_decrypt.txt");
out.write(encrypt.toByteArray());
out.close();
System.out.println(keyfile + "で、\n"
+ srcFile + "のファイルを復号し、\n"
+ srcFile + "_public_decrypt.txt のファイル生成終了");
}
}