質問: cipher.dofinal(input) あなたが自分でやる必要がある "todo"ビット:-)
回答: エリクソンの提案を読み、他のいくつかの投稿とこの例 here から何ができるかを収集した後、推奨される変更でdougのコードを更新しようとしました。改善するために自由に編集してください。 初期化ベクトルは修正されなくなりました 暗号化キーは、エリクソンのコードを使用して導出されます securerandom()を使用してsetupencrypt()で8バイトのソルトが生成されます 暗号化ソルトとパスワードから復号化キーが生成されます 復号化暗号は、復号化キーと初期化ベクトルから生成されます org.apache.commonsの代わりに16進数の調整を削除 codec hexルーチン いくつかの注意:これは128ビット暗号化キーを使用します-javaは明らかに256ビット暗号化をすぐに実行しません。 256を実装するには、javaインストールディレクトリにいくつかの追加ファイルをインストールする必要があります。また、私は暗号人間ではありません。気をつけて。import java.io.file; import java.io.fileinputstream; import java.io.fileoutputstream; import java.io.ioexception; import java.io.unsupportedencodingexception; import java.security.algorithmparameters; import java.security.invalidalgorithmparameterexception; import java.security.invalidkeyexception; import java.security.nosuchalgorithmexception; import java.security.securerandom; import java.security.spec.invalidkeyspecexception; import java.security.spec.invalidparameterspecexception; import java.security.spec.keyspec; import javax.crypto.badpaddingexception; import javax.crypto.cipher; import javax.crypto.cipherinputstream; import javax.crypto.cipheroutputstream; import javax.crypto.illegalblocksizeexception; import javax.crypto.nosuchpaddingexception; import javax.crypto.secretkey; import javax.crypto.secretkeyfactory; import javax.crypto.spec.ivparameterspec; import javax.crypto.spec.pbekeyspec; import javax.crypto.spec.secretkeyspec; import org.apache.commons.codec.decoderexception; import org.apache.commons.codec.binary.hex; public class crypto { string mpassword = null; public final static int salt_len = 8; byte [] minitvec = null; byte [] msalt = null; cipher mecipher = null; cipher mdecipher = null; private final int keylen_bits = 128; // see notes below where this is used. private final int iterations = 65536; private final int max_file_buf = 1024; /** * create an object with just the passphrase from the user. don't do anything else yet * @param password */ public crypto (string password) { mpassword = password; } /** * return the generated salt for this object * @return */ public byte [] getsalt () { return (msalt); } /** * return the initialization vector created from setupencryption * @return */ public byte [] getinitvec () { return (minitvec); } /** * debug/print messages * @param msg */ private void db (string msg) { system.out.println ("** crypt ** " + msg); } /** * this must be called after creating the initial crypto object. it creates a salt of salt_len bytes * and generates the salt bytes using securerandom(). the encryption secret key is created * along with the initialization vectory. the member variable mecipher is created to be used * by the class later on when either creating a cipheroutputstream, or encrypting a buffer * to be written to disk. * * @throws nosuchalgorithmexception * @throws invalidkeyspecexception * @throws nosuchpaddingexception * @throws invalidparameterspecexception * @throws illegalblocksizeexception * @throws badpaddingexception * @throws unsupportedencodingexception * @throws invalidkeyexception */ public void setupencrypt () throws nosuchalgorithmexception, invalidkeyspecexception, nosuchpaddingexception, invalidparameterspecexception, illegalblocksizeexception, badpaddingexception, unsupportedencodingexception, invalidkeyexception { secretkeyfactory factory = null; secretkey tmp = null; // crate securerandom salt and store as member var for later use msalt = new byte [salt_len]; securerandom rnd = new securerandom (); rnd.nextbytes (msalt); db ("generated salt :" + hex.encodehexstring (msalt)); factory = secretkeyfactory.getinstance("pbkdf2withhmacsha1"); /* derive the key, given password and salt. * * in order to do 256 bit crypto, you have to muck with the files for java's "unlimted security" * the end user must also install them (not compiled in) so beware. * see here: http://www.javamex.com/tutorials/cryptography/unrestricted_policy_files.shtml */ keyspec spec = new pbekeyspec (mpassword.tochararray (), msalt, iterations, keylen_bits); tmp = factory.generatesecret (spec); secretkey secret = new secretkeyspec (tmp.getencoded(), "aes"); /* create the encryption cipher object and store as a member variable */ mecipher = cipher.getinstance ("aes/cbc/pkcs5padding"); mecipher.init (cipher.encrypt_mode, secret); algorithmparameters params = mecipher.getparameters (); // get the initialization vectory and store as member var minitvec = params.getparameterspec (ivparameterspec.class).getiv(); db ("minitvec is :" + hex.encodehexstring (minitvec)); } /** * if a file is being decrypted, we need to know the pasword, the salt and the initialization vector (iv). * we have the password from initializing the class. pass the iv and salt here which is * obtained when encrypting the file initially. * * @param initvec * @param salt * @throws nosuchalgorithmexception * @throws invalidkeyspecexception * @throws nosuchpaddingexception * @throws invalidkeyexception * @throws invalidalgorithmparameterexception * @throws decoderexception */ public void setupdecrypt (string initvec, string salt) throws nosuchalgorithmexception, invalidkeyspecexception, nosuchpaddingexception, invalidkeyexception, invalidalgorithmparameterexception, decoderexception { secretkeyfactory factory = null; secretkey tmp = null; secretkey secret = null; // since we pass it as a string of input, convert to a actual byte buffer here msalt = hex.decodehex (salt.tochararray ()); db ("got salt " + hex.encodehexstring (msalt)); // get initialization vector from passed string minitvec = hex.decodehex (initvec.tochararray ()); db ("got initvector :" + hex.encodehexstring (minitvec)); /* derive the key, given password and salt. */ // in order to do 256 bit crypto, you have to muck with the files for java's "unlimted security" // the end user must also install them (not compiled in) so beware. // see here: // http://www.javamex.com/tutorials/cryptography/unrestricted_policy_files.shtml factory = secretkeyfactory.getinstance("pbkdf2withhmacsha1"); keyspec spec = new pbekeyspec(mpassword.tochararray (), msalt, iterations, keylen_bits); tmp = factory.generatesecret(spec); secret = new secretkeyspec(tmp.getencoded(), "aes"); /* decrypt the message, given derived key and initialization vector. */ mdecipher = cipher.getinstance("aes/cbc/pkcs5padding"); mdecipher.init(cipher.decrypt_mode, secret, new ivparameterspec(minitvec)); } /** * this is where we write out the actual encrypted data to disk using the cipher created in setupencrypt(). * pass two file objects representing the actual input (cleartext) and output file to be encrypted. * * there may be a way to write a cleartext header to the encrypted file containing the salt, but i ran * into uncertain problems with that. * * @param input - the cleartext file to be encrypted * @param output - the encrypted data file * @throws ioexception * @throws illegalblocksizeexception * @throws badpaddingexception */ public void writeencryptedfile (file input, file output) throws ioexception, illegalblocksizeexception, badpaddingexception { fileinputstream fin; fileoutputstream fout; long totalread = 0; int nread = 0; byte [] inbuf = new byte [max_file_buf]; fout = new fileoutputstream (output); fin = new fileinputstream (input); while ((nread = fin.read (inbuf)) > 0 ) { db ("read " + nread + " bytes"); totalread += nread; // create a buffer to write with the exact number of bytes read. otherwise a short read fills inbuf with 0x0 // and results in full blocks of max_file_buf being written. byte [] trimbuf = new byte [nread]; for (int i = 0; i < nread; i++) trimbuf[i] = inbuf[i]; // encrypt the buffer using the cipher obtained previosly byte [] tmp = mecipher.update (trimbuf); // i don't think this should happen, but just in case.. if (tmp != null) fout.write (tmp); } // finalize the encryption since we've done it in blocks of max_file_buf byte [] finalbuf = mecipher.dofinal (); if (finalbuf != null) fout.write (finalbuf); fout.flush(); fin.close(); fout.close(); db ("wrote " + totalread + " encrypted bytes"); } /** * read from the encrypted file (input) and turn the cipher back into cleartext. write the cleartext buffer back out * to disk as (output) file. * * i left cipherinputstream in here as a test to see if i could mix it with the update() and final() methods of encrypting * and still have a correctly decrypted file in the end. seems to work so left it in. * * @param input - file object representing encrypted data on disk * @param output - file object of cleartext data to write out after decrypting * @throws illegalblocksizeexception * @throws badpaddingexception * @throws ioexception */ public void readencryptedfile (file input, file output) throws illegalblocksizeexception, badpaddingexception, ioexception { fileinputstream fin; fileoutputstream fout; cipherinputstream cin; long totalread = 0; int nread = 0; byte [] inbuf = new byte [max_file_buf]; fout = new fileoutputstream (output); fin = new fileinputstream (input); // creating a decoding stream from the fileinputstream above using the cipher created from setupdecrypt() cin = new cipherinputstream (fin, mdecipher); while ((nread = cin.read (inbuf)) > 0 ) { db ("read " + nread + " bytes"); totalread += nread; // create a buffer to write with the exact number of bytes read. otherwise a short read fills inbuf with 0x0 byte [] trimbuf = new byte [nread]; for (int i = 0; i < nread; i++) trimbuf[i] = inbuf[i]; // write out the size-adjusted buffer fout.write (trimbuf); } fout.flush(); cin.close(); fin.close (); fout.close(); db ("wrote " + totalread + " encrypted bytes"); } /** * adding main() for usage demonstration. with member vars, some of the locals would not be needed */ public static void main(string [] args) { // create the input.txt file in the current directory before continuing file input = new file ("input.txt"); file eoutput = new file ("encrypted.aes"); file doutput = new file ("decrypted.txt"); string iv = null; string salt = null; crypto en = new crypto ("mypassword"); /* * setup encryption cipher using password. print out iv and salt */ try { en.setupencrypt (); iv = hex.encodehexstring (en.getinitvec ()).touppercase (); salt = hex.encodehexstring (en.getsalt ()).touppercase (); } catch (invalidkeyexception e) { e.printstacktrace(); } catch (nosuchalgorithmexception e) { e.printstacktrace(); } catch (invalidkeyspecexception e) { e.printstacktrace(); } catch (nosuchpaddingexception e) { e.printstacktrace(); } catch (invalidparameterspecexception e) { e.printstacktrace(); } catch (illegalblocksizeexception e) { e.printstacktrace(); } catch (badpaddingexception e) { e.printstacktrace(); } catch (unsupportedencodingexception e) { e.printstacktrace(); } /* * write out encrypted file */ try { en.writeencryptedfile (input, eoutput); system.out.printf ("file encrypted to " + eoutput.getname () + "\niv:" + iv + "\nsalt:" + salt + "\n\n"); } catch (illegalblocksizeexception e) { e.printstacktrace(); } catch (badpaddingexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } /* * decrypt file */ crypto dc = new crypto ("mypassword"); try { dc.setupdecrypt (iv, salt); } catch (invalidkeyexception e) { e.printstacktrace(); } catch (nosuchalgorithmexception e) { e.printstacktrace(); } catch (invalidkeyspecexception e) { e.printstacktrace(); } catch (nosuchpaddingexception e) { e.printstacktrace(); } catch (invalidalgorithmparameterexception e) { e.printstacktrace(); } catch (decoderexception e) { e.printstacktrace(); } /* * write out decrypted file */ try { dc.readencryptedfile (eoutput, doutput); system.out.println ("decryption finished to " + doutput.getname ()); } catch (illegalblocksizeexception e) { e.printstacktrace(); } catch (badpaddingexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } } }