Last active
January 8, 2021 06:39
-
-
Save yattom/a11d6d84a3d21eef6aee to your computer and use it in GitHub Desktop.
AES暗号・復号をJavaとRubyで実装したサンプルです。言語間で相互に暗号化・復号ができます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
鍵生成はPKCS#5のPBKDF2、HMAC SHA1です。 | |
暗号化はAES、CBC mode、鍵長128bit、iteration count 65536です。 | |
パスワードは「password」固定、saltは長さ8 octetで0x0001020304050607(Big Endian)です。 | |
ivの長さは128bit固定です(なんで固定なのかよくわかってない)。 | |
送信するメッセージは、iv:encrypted_messageの構成です。先頭16 octetがiv、残りが全部encrypted_message。 | |
Javaでもっと長い鍵を使うにはUnlimited Strength Jurisdiction Policyが必要です。http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html (使っていいのかどうかは調べていません。) | |
参考資料 | |
http://www.ietf.org/rfc/rfc2898.txt | |
http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/PKCS5.html | |
http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html | |
http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption#992413 | |
JavaならSpringを使うといいという話 http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption#19485874 | |
http://www.trustss.co.jp/Java/JEncrypt100.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'openssl' | |
require 'base64' | |
data = 'a secret data' | |
password = 'password' | |
salt = "\x00\x01\x02\x03\x04\x05\x06\x07" | |
cipher = OpenSSL::Cipher.new('AES-128-CBC') | |
cipher.encrypt | |
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, salt, 65536, 128) | |
iv = cipher.random_iv | |
encrypted = cipher.update(data) + cipher.final | |
message = Base64.encode64 iv + encrypted | |
# message = "r7VzgcVz5OdffaXyRpHW6jCOdziYSK0smgsHLa9Sp0EFYjCERvEqCopyb7Tf9YoyjCTIq5FnKa6C3cdM2Wq/vw==" | |
p message | |
decoded = Base64.decode64 message | |
iv = decoded[0..15] | |
encrypted = decoded[16..-1] | |
cipher = OpenSSL::Cipher.new('AES-128-CBC') | |
cipher.decrypt | |
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, salt, 65536, 128) | |
cipher.iv = iv | |
print cipher.update(encrypted) + cipher.final #=> 'a secret data' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.security.AlgorithmParameters; | |
import java.security.Key; | |
import java.security.SecureRandom; | |
import javax.crypto.*; | |
import javax.crypto.spec.*; | |
import java.security.spec.*; | |
import org.apache.commons.codec.binary.Base64; | |
public class Crypto { | |
static final public byte[] MASTER_KEY = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; | |
static public void dump(byte[] b, String title) { | |
System.out.println(title + ":"); | |
dump(b); | |
} | |
static public void dump(byte[] b) { | |
for (int i=0; i<b.length;i++) { | |
if(i % 16 == 0 && i > 0) { System.out.println(); } | |
if(i % 8 == 0) { System.out.print("| "); } | |
System.out.print(String.format("%02x ", b[i])); | |
} | |
System.out.println(); | |
System.out.println(); | |
} | |
static class Envelope { | |
public byte[] encryptedMessage; | |
public byte[] iv; | |
public Envelope() { | |
} | |
public Envelope(String message) { | |
Base64 base64 = new Base64(); | |
byte[] buf = base64.decode(message); | |
iv = new byte[16]; | |
System.arraycopy(buf, 0, iv, 0, iv.length); | |
encryptedMessage = new byte[buf.length - iv.length]; | |
System.arraycopy(buf, iv.length, encryptedMessage, 0, encryptedMessage.length); | |
} | |
public String toString() { | |
byte[] buf = new byte[iv.length + encryptedMessage.length]; | |
System.arraycopy(iv, 0, buf, 0, iv.length); | |
System.arraycopy(encryptedMessage, 0, buf, iv.length, encryptedMessage.length); | |
Base64 base64 = new Base64(); | |
return base64.encodeToString(buf); | |
} | |
} | |
public void cipher(String password, byte[] salt, String text) throws Exception { | |
String message = encrypt(password, salt, text); | |
System.out.println("message=" + message); | |
String plaintext = decrypt(password, salt, message); | |
System.out.println("decrypted=" + plaintext); | |
} | |
public String encrypt(String password, byte[] salt, String text) throws Exception { | |
/* Derive the key, given password and salt. */ | |
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); | |
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128); | |
SecretKey tmp = factory.generateSecret(spec); | |
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); | |
/* Encrypt the message. */ | |
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); | |
cipher.init(Cipher.ENCRYPT_MODE, secret); | |
AlgorithmParameters params = cipher.getParameters(); | |
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV(); | |
dump(iv, "iv"); | |
byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8")); | |
dump(ciphertext, "ciphertext"); | |
Envelope envelope = new Envelope(); | |
envelope.encryptedMessage = ciphertext; | |
envelope.iv = iv; | |
return envelope.toString(); | |
} | |
public String decrypt(String password, byte[] salt, String message) throws Exception { | |
Envelope envelope = new Envelope(message); | |
/* Derive the key, given password and salt. */ | |
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); | |
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128); | |
SecretKey tmp = factory.generateSecret(spec); | |
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); | |
/* Decrypt the message, given derived key and initialization vector. */ | |
Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); | |
decipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(envelope.iv)); | |
String plaintext = new String(decipher.doFinal(envelope.encryptedMessage)); | |
return plaintext; | |
} | |
static public void main(String[] args) throws Exception { | |
Crypto crypto = new Crypto(); | |
String password = "password"; | |
byte[] salt = new byte[] {0, 1, 2, 3, 4, 5, 6, 7}; | |
if(args[0].equals("encrypt")) { | |
String text = args[1]; | |
System.out.println(crypto.encrypt(password, salt, text)); | |
} else if(args[0].equals("decrypt")) { | |
String message = args[1]; | |
System.out.println(crypto.decrypt(password, salt, message)); | |
} else { | |
String text = args[0]; | |
crypto.cipher(password, salt, text); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% ruby cipher.rb | |
"NbCNPmlJUV0Og4j0lWb9MRg7GuXrLMbBheAE4fECJEw=\n" | |
a secret data% | |
% java Crypto decrypt "NbCNPmlJUV0Og4j0lWb9MRg7GuXrLMbBheAE4fECJEw=\n" | |
a secret data | |
% java Crypto encrypt "the quick brown fox jumps over a lazy dog" | |
iv: | |
| a3 e9 36 6a a1 30 11 01 | 51 00 32 f9 3a f8 af 26 | |
ciphertext: | |
| 73 a5 b2 8b 5b a0 47 40 | 82 b8 74 35 05 32 14 aa | |
| 3d 9c 8f 86 9a d0 74 27 | ab d6 f4 45 41 c1 aa 69 | |
| 4b f3 c8 8a 0e 0c c1 35 | 76 e6 ef f5 d3 2c 3a 71 | |
o+k2aqEwEQFRADL5OvivJnOlsotboEdAgrh0NQUyFKo9nI+GmtB0J6vW9EVBwappS/PIig4MwTV25u/10yw6cQ== | |
% <uncomment cipher.rb:27 and replace message> | |
% ruby cipher.rb | |
"o+k2aqEwEQFRADL5OvivJnOlsotboEdAgrh0NQUyFKo9nI+GmtB0J6vW9EVBwappS/PIig4MwTV25u/10yw6cQ==" | |
the quick brown fox jumps over a lazy dog% | |
% |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment