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 のファイル生成終了"); } }