• ベストアンサー

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)

noname#53515
noname#53515
  • Java
  • 回答数3
  • ありがとう数1

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

  • ベストアンサー
  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.2

> ただ、実行する度に暗号化した文字列が異なってしまいます。 > 変数の「enc_param_」も送信先に引き継がなければならないのでしょうか? 多分YESです。 手っ取り早く、ソースにハードコードしといて、常に同じsecurity.AlgorithmParametersを使用する手もあります。 例) import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.security.AlgorithmParameters; import sun.misc.BASE64Encoder; public class code { private final static String SECRET_PW = "key12345"; private final static byte[] enc_param_ = {4,8,-9,98,88,-115,5,-124,-69,31}; public static void main(String[] args) { try { String val1 = encrypt( args[0], SECRET_PW ); System.out.println(val1); System.out.println(decrypt( val1, SECRET_PW )); } catch (Exception e) { e.printStackTrace(); } } private static Cipher setup_cipher( int ci_mode, String secretKey ) throws Exception { SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES"); AlgorithmParameters saprm = AlgorithmParameters.getInstance("DES"); saprm.init( enc_param_ ); Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding"); cp.init( ci_mode, sks, saprm ); return cp; } public static String encrypt(String encValue, String secretKey) throws Exception { Cipher cp = setup_cipher( Cipher.ENCRYPT_MODE, secretKey ); return new BASE64Encoder().encodeBuffer(cp.doFinal(encValue.getBytes())); } public static String decrypt(String decValue, String secretKey) throws Exception { Cipher cp = setup_cipher( Cipher.DECRYPT_MODE, secretKey ); byte[] decArr = new sun.misc.BASE64Decoder().decodeBuffer(decValue); return new String(cp.doFinal(decArr)); } } >実は今回、秘密鍵を使用してパラメータを暗号化し、拠点Aと拠点BでHTTPで通信を行なう必要があります。 だったら、SSLを使う方が簡単では。

その他の回答 (2)

  • nfonfonfo
  • ベストアンサー率63% (12/19)
回答No.3

>ただ、実行する度に暗号化した文字列が異なってしまいます。 回答ではありませんが、CBCモードについていま一度勉強されてみてはいかがでしょうか? 参考サイトを参考にしてください。

参考URL:
http://www.ss.iij4u.or.jp/~somali/web/_block_mode.html
noname#53515
質問者

お礼

ご回答ありがとうございます。 下記の記述でProviderを追加するようにした所 毎回同じ値を作成することができました。 Security.addProvider(new com.sun.crypto.provider.SunJCE()); 回答をしてくださったみなさま ありがとうございました。

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.1

Sunのサンプルコードを見ると、 暗号化に使ったSecurityAlgorithmParametersを、復号に使う必要があります。ENCRYPT_MODEでinitした際に暗黙的に生成されてるみたい。 質問文のコードを改変したもの(☆が追加): import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.security.AlgorithmParameters; /* ☆ */ import sun.misc.BASE64Encoder; public class Main01 { private static byte[] enc_param_; /* ☆ */ public static void main(String[] args) { try { String val1 = encrypt( args[0], "key12345"); System.out.println(val1); System.out.println(decrypt(val1, "key12345")); } catch (Exception e) { e.printStackTrace(); } } public static String encrypt(String encValue, String secretKey) throws Exception { SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES"); Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding"); cp.init(Cipher.ENCRYPT_MODE, sks); enc_param_ = cp.getParameters().getEncoded(); /* ☆ */ return new BASE64Encoder().encodeBuffer(cp.doFinal(encValue.getBytes())); } public static String decrypt(String decValue, String secretKey) throws Exception { SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(), "DES"); Cipher cp = Cipher.getInstance("DES/CBC/PKCS5Padding"); AlgorithmParameters saprm = AlgorithmParameters.getInstance("DES"); /* ☆ */ saprm.init( enc_param_ ); /* ☆ */ cp.init(Cipher.DECRYPT_MODE, sks, saprm /* ☆ */ ); byte[] decArr = new sun.misc.BASE64Decoder().decodeBuffer(decValue); return new String(cp.doFinal(decArr)); } }

noname#53515
質問者

補足

osamuy様 早速の回答ありがとうございます。 いただいたソースを実行してみましたが、無事暗号、複合化を行なうことができました。 ただ、実行する度に暗号化した文字列が異なってしまいます。 これは回避不能なのでしょうか? 実は今回、秘密鍵を使用してパラメータを暗号化し、拠点Aと拠点BでHTTPで通信を行なう必要があります。 秘密鍵はお互いの外部ファイルに保持していますので、その鍵を使用して暗号、復号できればと考えているのです。 この場合、同じ秘密鍵を使用して暗号化したならば、必ず同じ暗号になりませんと送信先で復号できないと思っています。 DESを使用した暗号化/複合化の場合、秘密鍵をお互い保持しておくだけでなく 今回osamuy様追加した変数の「enc_param_」も送信先に引き継がなければならないのでしょうか? ≪いただいたソースの実行結果≫ 引数に「10000」を指定 【1回目】 暗号化後:6wc4lWqk4XI= 複合化後:10000 【2回目】 暗号化後:I58cD3SogT4= 複合化後:10000 【3回目】 暗号化後:w536VsFvHJY= 複合化後:10000

関連するQ&A

  • 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
  • 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
  • 暗号キーの保存

    現在下記のようにし、暗号化を行っています。 -------------------------以下ソース 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
  • 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
  • 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
  • Stringオブジェクトの文字コードの変換

    NewString = new String(b.getBytes("iso-8859-1"),"Shift_JIS"); でShift-Jisに変換できるとありましたが、どうも出力の 日本語部分が3Fになってしまってうまくいきません。 テスト用に以下のコードを作ってみました。 import java.io.File; import java.io.FileWriter; import java.io.BufferedWriter; import java.io.IOException; import java.io.FileOutputStream; public class Test { public static void main(String[] args) { try{ String regex_title; regex_title = "制限をしている場合"; System.out.println(getHexString(regex_title.getBytes())); System.out.println(getHexString(regex_title.getBytes("iso-8859-1"))); regex_title = "制限をしている場合"; regex_title = getUTF8(regex_title); System.out.println(getHexString(regex_title.getBytes())); System.out.println(getHexString(regex_title.getBytes("iso-8859-1"))); regex_title = "制限をしている場合"; regex_title = getShiftJIS(regex_title); System.out.println(getHexString(regex_title.getBytes())); System.out.println(getHexString(regex_title.getBytes("iso-8859-1"))); FileOutputStream fs = new FileOutputStream("./test.txt"); fs.write(regex_title.getBytes()); fs.close(); }catch(Exception ex){ } } public static String getHexString(byte[] b){ String buff=""; try{ for(int i=0;i<b.length;i++) buff += String.format("\\x%02x", b[i]); }catch(Exception ex){ } return buff; } public static String getUTF8(String b){ try { //UTF-8へ変換 return new String(b.getBytes(), "UTF-8"); } catch (Exception e) { e.printStackTrace(); return b; } } public static String getShiftJIS(String b){ try { //UTF-8へ変換 return new String(b.getBytes(),"Shift_JIS"); } catch (Exception e) { e.printStackTrace(); return b; } } // @Override } //////////////////////////////////////////////////////////// 1. System.out.println(getHexString(regex_title.getBytes("iso-8859-1"))); の部分の出力をみると3Fに変換されています。 regex_title.getBytes("iso-8859-1")の時点で3Fな事がわかります。 何故でしょうか? 私がやりたい事はStringの内部のコードをUTF8にする事です。 NewString = new String(b.getBytes("iso-8859-1"),"UTF-8"); では、出来ていないようでした。 2. また、以下のコードを実行するとtest.txt test2.txtともに 文字コードがShiftJisで出力されるのはなぜでしょうか? 変換を行わなければ内部処理形式のUnicodeで出力されるの ではないのでしょうか? regex_title = "制限をしている場合"; FileOutputStream fs = new FileOutputStream("./test.txt"); fs.write(regex_title.getBytes()); fs.close(); File file = new File("./test2.txt"); BufferedWriter bw = new BufferedWriter(new FileWriter(file)); bw.write(regex_title); bw.close(); 上はgetBytes()が変換してるのでしょうか? 下はBufferedWriterかFileWriterが変換してる? ではString内部のByteをそのまま出力するにはどうしたら・・・。

    • ベストアンサー
    • Java
  • 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
  • コマンドプロンプトを使用して。

    よろしくお願いいたします。ネット上にあったサンプルコードをコンパイルし、実行したところ 「Exception in thread "main"java.lang.NoSuchMethodError: main」というメッセージが表示されたのですがどういうことなのでしょうか? コードは以下の通りです。わかる方いましたらよろしくお願いいたします。 public class Sample { public static void main(String[] args1,String[] args2) { MyObject object = new MyObject(); object.setName("mikel"); String s = object.getName(); System.out.println(s); } } class MyObject { String name; public void setName(String str) { name = str; } public String getName() { return name; } }

    • ベストアンサー
    • Java
  • 例外(throws)について

    例外のthrowsがよくわかりません。 (例1) public static void main(String[] args) throws Exception { new testClass().testA(); } void testA() throws Exception { FileReader exFile = new FileReader("exFile.txt"); } (例2) public static void main(String[] args) throws FileNotFoundException { new testClass().testA(); } void testA() throws FileNotFoundException { FileReader exFile = new FileReader("exFile.txt"); } 上記2つの例ではどちらも 「java.io.FileNotFoundException: exFile.txt (指定されたファイルが見つかりません。)」 というログが出力されるようです。 throws ExceptionにしてもFileNotFoundExceptionと判別できるのならば、 あえてthrows FileNotFoundExceptionにする必要がなく、大抵の場合 throws Exceptionにしておけばよいと思うのですが、 その解釈は間違っているでしょうか?

    • ベストアンサー
    • Java
  • ファイルよりの文字列の取り込み(Properties)

    下記のプログラムでテキストファイルに"0x5C"を含む文字列を 取り込んだ時に文字化けしてしまいます。 テキストファイルに\\を付加する逃げ方は検索して発見しましたが \\を付加を付加せずに解決する方法は有りませんでしょうか? import java.io.FileInputStream; import java.util.Properties; public class Class1 {  public static void main (String[] args) {   try {    FileInputStream oFileInputStream = new FileInputStream("c:\\test.txt");    Properties oProperties = new Properties();    oProperties.load(oFileInputStream);    String sTmp1 = oProperties.getProperty("100001T");    String sBuf1 = new String(sTmp1.getBytes("8859_1"), "MS932");    String sBuf2 = new String(oProperties.getProperty("100001M").getBytes("8859_1"), "MS932");    System.out.println(sBuf1);    System.out.println(sBuf2);   } catch (Exception oException) {    oException.printStackTrace();   }  } } /* 実行結果 可狽ナす。可狽ナす。可狽ナす。可狽ナす。 可能です。 */ /* test.txtの内容 100001T=可能です。可能です。可能です。可能です。 100001M=可能\\です。 100001S=1 100001L=0 */

    • ベストアンサー
    • Java

専門家に質問してみよう