Javaで実装されたAES多重暗号化・復号化の安全性について

このQ&Aのポイント
  • Javaで実装されたAES多重暗号化・復号化の安全性について調査しました。
  • AES暗号化は順番に関わらず復号化できるため、メンタルポーカーアルゴリズムが実装できると考えましたが、詳しい安全性は不明です。
  • AES暗号化の安全性については知識がないので、スーパーコンピュータの手にかかれば解読できる可能性もあるかもしれません。
回答を見る
  • ベストアンサー

Java(AES)多重の暗号化・復号化、安全?

メンタル・ポーカー・アルゴリズム↓をJavaで実装したくて http://en.wikipedia.org/wiki/Mental_poker まず、暗号化について調べました。 AESという暗号化の方法を使ってみたのですが、 これなら、多重に暗号化したとして、順番に関わらず、 復号化できるようなので、メンタル・ポーカー・アルゴリズムが実装できると思いました。 しかしながら、私はこのAESという暗号化の方法について、詳しく知りません。 この暗号化方法は、安全なのでしょうか。たとえば、カギがなくとも、暗号前のデータの見当がつく かのようなことが、スーパーコンピュータの手にかかれば一時間もあれば分かってしまう、 というようなことはないでしょうか。 下記は、ランダムな順番で暗号化・復号化してみたコードです↓ 参考になればと思い乗せてみます static void shuffle(int[] array) { for (int i = 1; i < array.length; i++) { int n = random.nextInt(i + 1); int t = array[i]; array[i] = array[n]; array[n] = t; } } public void testAES() throws Exception { String alg = "AES"; byte[] orgData = "abcdefghhijklmno".getBytes(); KeyGenerator keygen = KeyGenerator.getInstance(alg); int keyCount = 16; Key[] keys = new Key[keyCount]; int[] encryptOrder = new int[keyCount]; int[] decryptOrder = new int[keyCount]; for (int i = 0; i < keyCount; i++) { keys[i] = keygen.generateKey(); encryptOrder[i] = i; decryptOrder[i] = i; } shuffle(encryptOrder); shuffle(decryptOrder); byte[][] ivs = new byte[keyCount][]; Cipher cipher = Cipher.getInstance(alg + "/OFB/NoPadding"); byte[] data = orgData.clone(); for (int i = 0; i < keyCount; i++) { int idx = encryptOrder[i]; cipher.init(Cipher.ENCRYPT_MODE, keys[idx]); ivs[idx] = cipher.getIV(); data = cipher.doFinal(data.clone()); } for (int i = 0; i < keyCount; i++) { int idx = decryptOrder[i]; cipher.init(Cipher.DECRYPT_MODE, keys[idx], new IvParameterSpec(ivs[idx])); data = cipher.doFinal(data); } assertTrue(new String(data), Arrays.equals(orgData, data)); }

  • Java
  • 回答数1
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

適切に使う限り,Rijndeal (AES) は対称鍵暗号としては現時点で現実的にみて一番安全なグループに入ると思います。 現時点ではDESのような現実的な時間での解読がなされたという報告はないはずです。 実際に問題となるようであれば,各種の警告が発せられるでしょうし,NISTなりが新たな対称鍵暗号を探すでしょう。 http://ja.wikipedia.org/wiki/AES暗号

narucy
質問者

お礼

ありがとうございます。 復号化の順番がバラバラでも、元文がわからない安全なAESって凄いですね。

関連するQ&A

  • JavaでXORによる暗号化

    JavaでXORによる暗号化について調べていたら下記URLのサイトを見つけました。 http://www.eeb.co.jp/2007/07/_10_1.html そこでサンプルにあった下記プログラムをvalue と key を変えて実行してみたところ value の中の「は」、「で」がうまく復元されず文字化けしてしまいました。 どこが悪いのかよくわからないのですがお分かりになられる方がいらっしゃいましたら 教えていただけますでしょうか。 public class XorTest { //================================================== // メイン //================================================== public static void main(String[] args) { String value = "abcd本日はお日柄もよろしいようで"; String key = "1"; // 暗号化前出力 print("暗号化前", value); // 暗号化 byte[] byteEncodeArray = encode(value.getBytes(), key); value = new String(byteEncodeArray); // 暗号化後出力 print("暗号化後", value); // 復元 byte[] byteDecodeArray = decode(value.getBytes(), key); value = new String(byteDecodeArray); // 復元後出力 print("復元後", value); } //================================================== // 暗号化 //================================================== private static byte[] encode(byte[] src, String key) { byte[] byteKeyArray = new byte[0]; byte[] byteEncArray = new byte[src.length]; // キーの文字列を変換する文字列をカバーするまで繰り返す while(byteKeyArray.length < src.length) { byteKeyArray = (new String(byteKeyArray) + key).getBytes(); } // 変換 for (int i = 0; i < src.length; i++) { byteEncArray[i] = (byte)(src[i]^byteKeyArray[i]); } return byteEncArray; } //================================================== // 復元 //================================================== private static byte[] decode(byte[] src, String key) { return encode(src, key); } //================================================== // ダンプ文字列取得 //================================================== private static String getDump16(byte[] value) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < value.length; i++) { String hex = Integer.toHexString((int)value[i] & 255); // 4桁に揃える hex = "0000" + hex; hex = hex.substring(hex.length() - 4, hex.length()); // バッファに追加(空白区切り、10桁ずつ改行) buf.append(hex + (i % 10 == 9?System.getProperty("line.separator"):" ")); } return buf.toString().trim(); } private static void print(String title, String value) { System.out.println("【 " + title + " 】"); System.out.println("-----------------------------"); System.out.println(value); System.out.println(getDump16(value.getBytes())); System.out.println(); System.out.println(); } }

    • ベストアンサー
    • Java
  • JavaからVBScriptへのAES暗号化によるデータ渡し

    javaで作られたサイトからVBScriptで作られたサイトへサイレントログインするシステムを構築しています。 その際にログインIDをAES(キー長128bit、ECBモード)で暗号化し渡そうと考えています。 javaではCipherクラスで暗号化し、aspではCAPICOMで復号化しようとしているのですが、うまくいきません。 そもそも同じ平文と鍵で暗号化しても同じ暗号文になりません。(javaはbase64に変換しています。CAPICOMが間違っているような気はしているのですが、参考になるものが少なくて困っています。) CAPICOMはhttp://apis.jpn.ph/fswiki/wiki.cgi?page=ScrapCode%2FVBS%2FConvertのサンプル通りにやっています。 CAPICOMでもjavaでも同じ暗号化方式ならば同じ結果が返ってくるべきだと思うのですが、認識違いますか? どうすれば、同じ暗号文が取得できるのでしょうか? また、java-VBScript間のAES暗号でのデータ渡しについて、 違う方式で可能ならば教えてください。 よろしくお願いします。

  • 暗号キーの保存

    現在下記のようにし、暗号化を行っています。 -------------------------以下ソース KeyGenerator kg = KeyGenerator.getInstance("AES"); SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); // 128ビットで暗号化 kg.init(128, random); Key key = kg.generateKey(); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); // バイト配列に変換 byte[] byteArray = cipher.doFinal(argStr.getBytes()); 暗号化について調べていると、暗号化(復号化)キーは乱数などで作ったほうが良いと書いてありました。 そこで質問なのですが、ログイン画面でパスワードを暗号化するために上記コーディングを行っているのですが、乱数でキーを作成した場合、各ユーザごとにキーが作成されるって認識であってますでしょうか? その場合、暗号キーはどこに保存しておくのが望ましいでしょうか? できる限りセキュアなアプリを作りたいと思っています。 (もちろん100%はないとは思っていますので) ※データベースは使えない環境を想定しています。 以上宜しくお願いします。 tomcat5.0 jdk.1.4.2 を使用

    • ベストアンサー
    • Java
  • 暗号利用モードの実装

    C言語でAESのEBCモードを実装しようとしています。 unsigned char key[32]; int w[60]; int data[NB]; int nk; int nr; int data2[32]; int Cipher(int *); int invCipher(int *); void encryptEBC(int *,int n); void decryptEBC(int *,int n); main(){ unsigned char keys[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; unsigned char iv[]={0xcb,0x70,0x05,0x9e,0x27,0x2f,0x4e,0xd2, 0xd0,0xbe,0x0b,0x06,0xbf,0x16,0xec,0x5a}; unsigned char init2[]={'1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0', '1','2','3','4','5','6','7','8','9','0',0x0a}; int isize = sizeof(init2)/sizeof(init2[0]); int dsize2 = sizeof(data2)/sizeof(data2[0]); printf("%d,%d\n",isize,dsize2); FILE *fp; char *fname = "test.txt"; unsigned char init[16]; int i = 0; int c; fp = fopen( fname, "r" ); if( fp == NULL ){ printf( "%sファイルが開けません\n", fname ); return -1; } while( (c = fgetc( fp )) != EOF ){ init[i] = c; i = i+1; } fclose( fp ); memcpy(key,keys,16); nk = 4; nr = nk + 6; KeyExpansion(key); memcpy(data,init,16); memcpy(data2,init2,isize); datadump("PLAINTEXT: ",data,16); datadump("KEY: ",key,16); Cipher(data); datadump("Cipher: ",data,16); invCipher(data); datadump("invCipher: ",data,16); printf("\n"); datadump("PLAINTEXT: ",data2,dsize2); encryptEBC(data2,dsize2); datadump("EBCCipher: ",data2,dsize2); decryptEBC(data2,dsize2); datadump("invCipher: ",data2,dsize2); printf("\n"); return 0; } void encryptEBC(int data[],int dsize){ int tmp[16]; int i,j,k; printf("aiu%d\n",dsize); KeyExpansion(key); for (i = 0; i < dsize; i += 16) { memcpy(tmp,&data[i],16); Cipher(tmp); memcpy(&data[i],tmp,16); } } void decryptEBC(int data[],int dsize){ int tmp[16]; int i,j,k; printf("eo%d\n",dsize); KeyExpansion(key); for (i = 0; i < dsize; i += 16) { memcpy(tmp,&data[i],16); invCipher(tmp); memcpy(&data[i],tmp,16); } } このようなプログラムでとりあえず2ブロック分の暗号化、復号を行おうと思っているのですが、1ブロック目しか行えません。 どなたかどこが悪いのかご教授いただけないでしょうか?

  • Ruby 暗号化したファイルの復号について

    Rubyでファイルを暗号化し、それを復号したいのですがうまくいかないため、 質問させていただきます。 Ruby 1.9.3を使用しています。 ・ファイルの暗号化 encrypt.rb ------------------------------------------------- # encoding: cp932 require 'openssl' def encrypt(file, pass)   enc = OpenSSL::Cipher::AES256.new('CBC')   enc.encrypt   enc.pkcs5_keyivgen(pass)   File.open(file, 'rb') do |fin|     File.open("#{file}.sec", 'wb') do |fout|       while buff = fin.read(8000)         fout.write(enc.update(buff))       end       fout.write(enc.final)     end   end   enc.reset end if $*.length > 0   print 'password: '   pass = $stdin.gets.chomp   $*.each do |arg|     begin       encrypt(arg, pass)       puts "#{arg}を暗号化したファイル#{arg}.secを作りました。"     rescue       puts "#{arg}の暗号化に失敗しました。"     end   end   0.upto(pass.length - 1) do |i|     pass[i] = '\xff'   end end ------------------------------------------------- ・ファイルの復号 decrypt.rb ------------------------------------------------- # encoding: cp932 def decrypt(file, pass)   dec = OpenSSL::Cipher::AES256.new('CBC')   dec.decrypt   dec.pkcs5_keyivgen(pass)   File.open(file, 'rb') do |fin|     File.open("#{file}.plain", 'wb') do |fout|       while buff = fin.read(512)         fout.write(dec.update(buff))       end       fout.write(dec.final)     end   end   dec.reset end if $*.length > 0   print 'password: '   pass = $stdin.gets.chomp   $*.each do |arg|     begin       decrypt(arg, pass)       puts "#{arg}を復号したファイル#{arg}.plainを作りました。"     rescue       puts "#{arg}の復号に失敗しました。"     end   end   0.upto(pass.length - 1) do |i|     pass[i] = '\xff'   end end ------------------------------------------------- コマンドプロンプトでencrypt.rb自身を暗号化し、encrypt.rb.secの作成はできるのですが、 decrypt.rbを実行してパスワードを入力しても復号ができません。 どのようにすれば復号できるのか教えていただけますでしょうか。

    • ベストアンサー
    • Ruby
  • DESを使用した暗号化/復号化処理について

    現在下記仕様でパラメータの暗号化複合化処理を作成していますが例外が発生して困っています。 方式:DES モード:CBC パディング:PKCS5Padding 秘密鍵:kagi1234 BASE64でエンコードしてString変換 【例外内容】 Exception in thread "main" java.lang.RuntimeException: java.security.InvalidKeyException: Parameters missing at enc.Main01.decrypt(Main01.java:114) 【ソースコード】 import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Encoder; public class Main01 { public static void main(String[] args) { try { String val1 = encrypt("10000", "key12345"); System.out.println(decrypt(val1, "key12345")); } catch (Exception e) { e.printStackTrace(); } } public static String encrypt(String text, String secretKey) throws Exception { SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES"); Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding"); cp.init(Cipher.ENCRYPT_MODE, sks); return new BASE64Encoder().encodeBuffer(cp.doFinal(text.getBytes())); } public static String decrypt(String decValue, String secretKey) throws Exception { SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES"); byte[] decArr = new sun.misc.BASE64Decoder().decodeBuffer(decValue); Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding"); cp.init(Cipher.DECRYPT_MODE, sks); return new String(cp.doFinal(decArr)); } } 対処方法がも解らず自力解決は困難です。 お手数ですが解決方法を御教授願えないでしょうか? よろしくお願いします。 環境(WidowsXP SP2, JDK1.5.0_07-b03)

    • ベストアンサー
    • Java
  • javaについて質問です。

    javaについて質問です。 シーザー暗号の暗号化と復号化のプログラムをつくりたいのですが... import java.io.*; class Prob6_2 { public static void main(String [] args)throws IOException { int key; //キー番号 String orgStr; //ターゲット文字列 String encStr; //暗号化文字列 String decStr; // 復号化文字列 String temp; BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); System.out.print("ターゲット文字列:"); orgStr=br.readLine(); System.out.print("キー番号:"); temp=br.readLine(); key=Integer.parseInt(temp); Cipher cip=new Cipher (); encStr=cip.encrypt(orgStr,key); decStr=cip.decrypt(encStr,key); System.out.println("[Original Code]"+orgStr); System.out.println("[Encrypted Code]"+encStr); System.out.println("[Decrypted Code]"+decStr); } } class Cipher { String encrypt(String str,int key) { for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c+key); /*この後どのように一つずつの文字をつなげて文字列にしたら良いか分かりません。StringBuffer クラスのインスタンス をつかうといいというヒントは問題集に書いてあるのですが....教えて下さい*/ } } String decrypt(String str,int key) { for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c-key); /*この後どのように一つずつの文字をつなげて文字列にしたら良いか分かりません。StringBuffer クラスのインスタンス をつかうといいというヒントは問題集に書いてあるのですが....教えて下さい*/ } } } class Cipherのところにコメントでも書いてあるのですが、一つずつの文字をつなげて文字列にしたら良いか分かりません。どのように実現したら良いのでしょうか?><教えてください>< 違っているところがあればそこも教えて頂けるとたすかります。 お願いします>< できたらStringBufferをつかったやり方を教えてください><」

    • ベストアンサー
    • Java
  • CBCモードの実装

    void encryptCBC(int data[],int dsize,int iv[]){ //暗号化 int tmp[4]; int i,j; KeyExpansion(key); for (i = 0; i < dsize; i += 4) { memcpy(tmp,&data[i],16); for(j=0;j<4;j++){ tmp[j]^=iv[j]; //16バイトごとに区切ったデータとベクタの排他的論理和 } Cipher(tmp); //暗号化 memcpy(&data[i],tmp,16); memcpy(iv,tmp,16); //ベクタの更新 } } void decryptCBC(int data[],int dsize,int iv[]){ //復号 int tmp[4]; int v[4]; int i,j; KeyExpansion(key); for (i = 0; i < dsize; i += 4) { memcpy(tmp,&data[i],16); invCipher(tmp);  //復号 if(i==0){ //初期ベクタとの排他的論理和 for(j=0;j<4;j++){ tmp[j]^=iv[j]; } }else{ //更新したベクタとの排他的論理和 for (j=0;j<4;j++){ tmp[j]^=v[j]; } } memcpy(v,&data[i],16); //ベクタの更新 memcpy(&data[i],tmp,16); } } AESのCBCモードでの暗号化、復号を実装しようとしています。 2ブロック目以降は正しく復号できているのですが、1ブロック目が元の値に戻りません。 どこが間違っているかどなたか教えていただけないでしょうか?

  • byte配列の途中から2個ずつintに移すには?

    byte配列の途中から2個ずつintに移すには? Byte[] recvData={02:03:04:05:06:01:00:02:00:FF:FF:05} int nCount; =3;//データn個ください。 List<int> ValueList = new List<int>();//格納用 for (int i = 0; i < nCount; i++) {   //[0]~[4]までヘッダ+サブヘッダ。データは[5]から2byteずつ ValueList.Add(recvData[5 + i * 2] | (recvData[6 + i * 2] << 3)); }; という感じで、溜まったbyte配列の受信データから 0001、0002、65535とデータ部分を2byteずつ取り出したいのですが もうちょっとC#なら簡潔な書き方ってあるのでしょうか?

  • javaについて質問です。お願いします><

    javaについて質問です。お願いします>< シーザー暗号を実現するプログラムをじゃいたのですが、import java.io.*; class Prob6_3 { public static void main(String [] args)throws IOException { int key; //キー番号 String orgStr; //ターゲット文字列 String encStr; //暗号化文字列 String decStr; // 復号化文字列 String temp; BufferedReader br= new BufferedReader(new InputStreamReader(System.in)); System.out.print("ターゲット文字列:"); orgStr=br.readLine(); System.out.print("キー番号:"); temp=br.readLine(); key=Integer.parseInt(temp); Cipher cip=new Cipher (); encStr=cip.encrypt(orgStr,key); decStr=cip.decrypt(encStr,key); System.out.println("[Original Code]"+orgStr); System.out.println("[Encrypted Code]"+encStr); System.out.println("[Decrypted Code]"+decStr); } } class Cipher { String encrypt(String str,int key) { String ret="";             //ココです1 for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c+key); ret+=c; } return ret; } String decrypt(String str,int key) { String ret="";              //ここです2 for(int i=0;i<str.length();i++){ char c=str.charAt(i); c=(char)((int)c-key); ret+=c; } return ret; } }   とこんな感じになり実行もできるのですが、class CipherのString encrypt(String str,int key)やString decrypt(String str,int key)のところで一つずつ文字をつなげて文字列にするにはStringBufferクラスのインスタンスを利用すると簡単だとききました。だけど記述方法がよくわからなく使用した場合のreturn文の書き方もイマイチわかりません><なのでできるだけ詳しく教えて頂けないでしょうか??お願いします。//ココですと書いてあるところです。お願いします><

    • ベストアンサー
    • Java

専門家に質問してみよう