ããã¯ããªã«ãããããŠæžãããã®ïŒ
ãã¡ãã®ãšã³ããªãæžããŠããŠããJavaã§AESã䜿ãæã®ã³ãŒããå šç¶èŠããŠãªããªããšæããŸããŠã
MessageDigestに"SHA"とか、Cipherに"AES"とだけ指定した場合、どうなるの? - CLOVER🍀
ã¡ã¢ããŠãããããªããšã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã§ãã
$ java --version openjdk 11.0.9.1 2020-11-04 OpenJDK Runtime Environment (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04) OpenJDK 64-Bit Server VM (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04, mixed mode, sharing) $ mvn --version Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 11.0.9.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-60-generic", arch: "amd64", family: "unix"
Javaã§AESã䜿ã
Javaã§AESãæ±ãã«ã¯ãCipher
ã¯ã©ã¹ãäž»ãšããŠäœ¿ããŸãã
Javaæå·åã¢ãŒããã¯ãã£(JCA)ãªãã¡ã¬ã³ã¹ã»ã¬ã€ã / Cipherã¯ã©ã¹
ããšããã¡ããã
KeyGenerator (Java SE 11 & JDK 11 )
SecretKeySpec (Java SE 11 & JDK 11 )
IvParameterSpec (Java SE 11 & JDK 11 )
ä»åãã¢ã«ãŽãªãºã ãã¢ãŒããããã£ã³ã°ã¯ä»¥äžã®2ã€ã䜿ã£ãŠããã°ã©ã ãæžãããšã«ããŸãããã
AES/ECB/PKCS5Padding
AES/CBC/PKCS5Padding
éµã®é·ãã¯æåã¯128ãããã§è¡ããæåŸã«192ãããã256ããããŸã§æ±ããŸãã
ããã£ã³ã°ãªãã®å Žåãšãä»ã®ã¢ãŒãã¯ä»åã¯èããªãããšã«ããŸãã
Javaã»ãã¥ãªãã£æšæºã¢ã«ãŽãªãºã å / Cipherã¢ã«ãŽãªãºã å
JDKãããã€ãã»ããã¥ã¡ã³ã / SunJCEãããã€ã
ãã®åæã§ããã¹ãã³ãŒãã§äœ¿ãæ¹ãã¡ã¢ããŠãããããªããšã
ãã¹ãã³ãŒãã¯ã䜿çšããã¯ã©ã¹ãå€ãã€ã€ãæå·åããå€ã埩å·ã§ãããšãããŸã§ã確èªããŸãã
æºå
ãã¹ãã³ãŒãçšã«JUnit 5ãšAssertJãäŸåé¢ä¿ã«è¿œå ããMaven Surefire Pluginã®èšå®ãè¡ããŸãã
<dependencies> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.18.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.7.0</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> </plugin> </plugins> </build>
ãã¹ãã³ãŒãã®é圢ã¯ããã¡ãã
src/test/java/org/littlewings/aes/AesEncryptDecryptTest.java
package org.littlewings.aes; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; public class AesEncryptDecryptTest { // ããã«ããã¹ããæžãïŒïŒ }
ã§ã¯ãæžããŠãããŸãããã
KeyGeneratorã䜿ã£ãŠç§å¯éµãäœæãã
AESã¯å
±ééµæå·ã¢ã«ãŽãªãºã ãªããã§ãããç§å¯éµã®äœæãKeyGenerator
ã«ä»»ããããšãã§ããŸãã
KeyGenerator (Java SE 11 & JDK 11 )
Javaæå·åã¢ãŒããã¯ãã£(JCA)ãªãã¡ã¬ã³ã¹ã»ã¬ã€ã / KeyGeneratorã¯ã©ã¹
AES/ECB/PKCS5Padding
ã䜿ãå Žåã
@Test public void ecbUsingKeyGenerator() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // SecretKey int keySizeAsBit = 128; // 128 bit KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(keySizeAsBit); SecretKey secretKey = keyGenerator.generateKey(); // encrypt Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); encryptor.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); decryptor.init(Cipher.DECRYPT_MODE, secretKey); byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
æå·å察象ã®å€ã¯ããããã®ãã¹ãã±ãŒã¹ã§ããã®å€ã«ããŸãã
byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8);
KeyGenerator
ã䜿çšãããç§å¯éµã®çæã¯ãã¡ãã
// SecretKey int keySizeAsBit = 128; // 128 bit KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(keySizeAsBit); SecretKey secretKey = keyGenerator.generateKey();
KeyGenerator#getInstance
ã®åŒæ°ã«ã©ã®ã¢ã«ãŽãªãºã çšã®ããŒãäœãã®ããæå®ããå¿
èŠãããã®ã§ãããAES
ãšã ãæå®ããŸãã
ãã®éšåã«é¢ããŠã¯ãã¢ãŒããããã£ã³ã°ã¯é¢ä¿ãããŸããã
Javaã»ãã¥ãªãã£æšæºã¢ã«ãŽãªãºã å / KeyGeneratorã¢ã«ãŽãªãºã
KeyGenerator#init
ã§ã¯ãäœæããç§å¯éµã®ãµã€ãºãæå®ããŸããä»åã¯éµã®ãµã€ãºã¯128ããããªã®ã§ã128
ãšæå®ããŸãã
æåŸã«KeyGenerator#generateKey
ãåŒã³åºããšãSecretKey
ãããªãã¡ç§å¯éµãäœæãããŸãã
ããšã¯ãæå·åããŸãã
// encrypt Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); encryptor.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encrypted = encryptor.doFinal(value);
埩å·ã®éã«ã¯ãåãç§å¯éµã䜿ããŸãã
// decrypt Cipher decryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); decryptor.init(Cipher.DECRYPT_MODE, secretKey); byte[] decrypted = decryptor.doFinal(encrypted);
AES/CBC/PKCS5Padding
ã®å Žåã¯ãã¡ãã
@Test public void cbcUsingKeyGeneratorNoProvideIv() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // SecretKey int keySizeAsBit = 128; // 128 bit KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(keySizeAsBit); SecretKey secretKey = keyGenerator.generateKey(); // encrypt Cipher encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); encryptor.init(Cipher.ENCRYPT_MODE, secretKey); byte[] ivBytes = encryptor.getIV(); // auto generate byte[] encrypted = encryptor.doFinal(value); assertThat(ivBytes).hasSize(16); // block size assertThat(ivBytes).hasSize(encryptor.getBlockSize()); // block size // decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec iv = new IvParameterSpec(ivBytes); decryptor.init(Cipher.DECRYPT_MODE, secretKey, iv); // iv required byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
CBCã®å ŽåãIVïŒåæåãã¯ãã«ïŒãå¿ èŠã«ãªããŸãã
Cipher#init
æã«IVãæ瀺çã«äžããªãå Žåã¯ã©ã³ãã ã«äœæãããŸããããã®IVã¯åŸ©å·æã«å¿
èŠã«ãªããŸãã
ãã£ãŠãçæãããIVãååŸããå¿
èŠããããŸãïŒCipher#getIV
ïŒã
byte[] ivBytes = encryptor.getIV(); // auto generate
IVãäœã£ãŠããã®ã¯ãããã§ããã
åŸãããIVïŒãã€ãé
åïŒã¯ãIvParameterSpec
ã®ã€ã³ã¹ã¿ã³ã¹çæã«äœ¿ããŸãã
IvParameterSpec (Java SE 11 & JDK 11 )
// decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec iv = new IvParameterSpec(ivBytes);
ãã®IvParameterSpec
ãCipher#init
æã«äžãã埩å·ãè¡ããŸããæå·åã«äœ¿çšããIVãªãã§ã¯ã埩å·ã§ããŸããã
decryptor.init(Cipher.DECRYPT_MODE, secretKey, iv); // iv required byte[] decrypted = decryptor.doFinal(encrypted);
KeyGenerator
ã«é¢ããŠã¯ããããªæãã§ã
ã¡ãªã¿ã«ãKeyGenerator
ãå®éã«ç§å¯éµãäœæãäŸé Œããã®ã¯AESKeyGenerator
ãªã®ã§ããããã¡ãã¯SecureRandom#nextBytes
ã
䜿ã£ãŠããã ãã ã£ããããŸãã
SecretKeySpecã䜿ã£ãŠç§å¯éµãäœã
次ã¯ãScretKeySpec
ã䜿ã£ãŠç§å¯éµãäœã£ãŠã¿ãŸããå
ã»ã©ã¯KeyGenerator
ã«ç§å¯éµã®äœæãå®å
šã«ä»»ããŸãããã
ãã¡ãã¯ç§å¯éµã®ããŒã¿ãèªåã§çšæããããšã«ãªããŸãã
SecretKeySpec (Java SE 11 & JDK 11 )
Javaæå·åã¢ãŒããã¯ãã£(JCA)ãªãã¡ã¬ã³ã¹ã»ã¬ã€ã / KeySpecã€ã³ã¿ãã§ãŒã¹
ãŸãã¯AES/ECB/PKCS5Padding
ããã
@Test public void ecbUseUserDefinedSecretKey() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 16; // 128 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey); byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey); byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
ç§å¯éµãšãªã16ãã€ãïŒ128ãããïŒåã®ãã€ãé
åãå¿
èŠãªã®ã§ãããä»åã¯SecureRandom
ã§äœãããšã«ããŸããã
// User Defined SecretKey int keySize = 16; // 128 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes);
ãŸãããã®æ¹æ³ãéžãã æç¹ã§å
ã»ã©ã®KeyGenerator
ãšãã£ãŠããããšã¯å€ãããªãã®ã§ãããéµã®ããŒã¿ãèªåã§çšæããäœã§
ä»åã¯æžããŠããŸãã
ãã®ãã€ãé
åã¯ãSecretKeySpec
ã®ã³ã³ã¹ãã©ã¯ã¿ã«åŒãæž¡ããŸãã2ã€ç®ã®åŒæ°ã«ã¯AES
ãšæå®ããŸãããã¡ããKeyGenerator
ã®æãš
åæ§ã«ãã¢ãŒããããã£ã³ã°ã«ã€ããŠã¯é¢ä¿ãªãAES
ãšã ãæå®ããã°OKã§ãã
SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES");
ããšã¯ãKeyGenerator
ã䜿ã£ãå Žåãšåãã§ãã
AES/CBC/PKCS5Padding
ã®å Žåã¯ããã¡ãã
@Test public void cbcUseUserDefinedSecretKeyNoProvideIv() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 16; // 128 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey); byte[] ivBytes = encryptor.getIV(); // auto generate byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec iv = new IvParameterSpec(ivBytes); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey, iv); // iv required byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
KeyGenerator
ã䜿ã£ãŠããéšåãSecretKeySpec
ã䜿ãå
容ã«æžãæãã£ãŠããã ããªã®ã§ãç¹æ®µå€ãã£ããšããã¯
ãããŸããã
ãªããSecretKeySpec
äœææã«äœ¿ã£ããã€ãé
åã¯SecretKey#getEncoded
ã§åãåºããŸãããAESã®éµã
KeyGenerator#generateKey
ã§äœã£ãå Žåã«åŸãããã®ãSecretKeySpec
ã§ãã
@Test public void secretKeySpecEncodedBytes() throws NoSuchAlgorithmException { // direct SecretKeySpec int keySize = 16; // 128 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); SecretKey secretKey = new SecretKeySpec(secretKeyBytes, "AES"); assertThat(secretKeyBytes).isEqualTo(secretKey.getEncoded()); // KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(keySize * 8); SecretKey secretKeyFromKeyGenerator = keyGenerator.generateKey(); assertThat(secretKeyFromKeyGenerator).isInstanceOf(SecretKeySpec.class); }
ãªã®ã§ãç§å¯éµã®äœæã ãKeyGenerator
ã§è¡ã£ãŠãçæãããã€ãé
åãåŸããåãåºããšããã®ãã§ããŸãããšã
IvParameterSpecã䜿ã£ãŠIVïŒåæåãã¯ãã«ïŒãæå®ãã
CBCã®ãããªãIVïŒåæåãã¯ãã«ïŒãå¿
èŠãšããã¢ãŒãã®å Žåã®è©±ã§ãããããŸã§ã¯ãæå·åããæã«IVã¯Cipher
ã«
çæããŠããã£ãŠããŸããããããã§ã¯IVãèªåã§çšæããããšã«ããŸãã
䜿ãã®ã¯ãIvParameterSpec
ã¯ã©ã¹ã§ãã
IvParameterSpec (Java SE 11 & JDK 11 )
äœæããã³ãŒãã¯ãã¡ããAES/CBC/PKCS5Padding
ã§ãã
@Test public void cbcUseUserDefinedSecretKeyProvideIv() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 16; // 128 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // Initial Vector int blockSize = 16; byte[] ivBytes = new byte[blockSize]; random.nextBytes(ivBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); assertThat(encryptor.getBlockSize()).isEqualTo(blockSize); // block-size = 16 byte SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec encryptIv = new IvParameterSpec(ivBytes); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey, encryptIv); // using iv byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec decryptIv = new IvParameterSpec(ivBytes); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey, decryptIv); // using iv byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
IVçšã®ããŒã¿ã¯ããããã¯ãµã€ãºïŒ16ãã€ãïŒçšæããŸããä»åã¯ãä»ã«ç¿ã£ãŠSecureRandom
ã§çšæããŸããã
// Initial Vector int blockSize = 16; byte[] ivBytes = new byte[blockSize]; random.nextBytes(ivBytes);
ãããã¯ãµã€ãºã¯ãCipher
ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããåŸã§ããã°Cipher#getBlockSize
ã§åŸãããšãã§ããŸãã
assertThat(encryptor.getBlockSize()).isEqualTo(blockSize); // block-size = 16 byte
AESã®ãããã¯ãµã€ãºã¯ã16ãã€ãã§åºå®ã§ãã
IVãšããŠçšæãããã€ãé
åã¯ãIvParameterSpec
ã®ã³ã³ã¹ãã©ã¯ã¿ã«æž¡ããŠã€ã³ã¹ã¿ã³ã¹ãäœæããCipher#init
ã®åŒæ°ãšããŠ
䜿ããŸãã
IvParameterSpec encryptIv = new IvParameterSpec(ivBytes); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey, encryptIv); // using iv byte[] encrypted = encryptor.doFinal(value);
埩å·ã®æããåãIVã®å€ã䜿ããŸãã
// decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec decryptIv = new IvParameterSpec(ivBytes); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey, decryptIv); // using iv byte[] decrypted = decryptor.doFinal(encrypted);
AESãæ±ãæã«äœ¿ããããªã¯ã©ã¹ã¯ããããªæãã§ã¯ãªãã§ããããã
128ããã以å€ã®éµã䜿ã
AESã¯éµã®é·ããšããŠã128ãããã192ãããã256ãããã®3ã€ãå©çšã§ããŸãã
Java 9ããåã¯128ããã以å€ã®éµã䜿ãå Žåã¯å€æŽäœæ¥ãå¿ èŠã ã£ãã®ã§ãããJava 9以éã¯ããã©ã«ãã§äœ¿ããããã«ãªã£ãŠããŸãã
Javaæå·åã¢ãŒããã¯ãã£(JCA)ãªãã¡ã¬ã³ã¹ã»ã¬ã€ã / æå·åŒ·åºŠã®æ§æ
$JAVA_HOME/conf/security/java.security
ãšãããã¡ã€ã«ã®crypto.policy
ããããã£ããunlimited
ã«ãªã£ãããã§ãã
$ grep ^crypto.policy /usr/lib/jvm/java-11-openjdk-amd64/conf/security/java.security crypto.policy=unlimited
$JAVA_HOME/conf/security/java.security
ãã¡ã€ã«å
ã®ãcrypto.policy
ã®ã³ã¡ã³ããèšèŒããŠãããŸãã
# # Cryptographic Jurisdiction Policy defaults # # Import and export control rules on cryptographic software vary from # country to country. By default, Java provides two different sets of # cryptographic policy files[1]: # # unlimited: These policy files contain no restrictions on cryptographic # strengths or algorithms # # limited: These policy files contain more restricted cryptographic # strengths # # The default setting is determined by the value of the "crypto.policy" # Security property below. If your country or usage requires the # traditional restrictive policy, the "limited" Java cryptographic # policy is still available and may be appropriate for your environment. # # If you have restrictions that do not fit either use case mentioned # above, Java provides the capability to customize these policy files. # The "crypto.policy" security property points to a subdirectory # within <java-home>/conf/security/policy/ which can be customized. # Please see the <java-home>/conf/security/policy/README.txt file or consult # the Java Security Guide/JCA documentation for more information. # # YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY # TO DETERMINE THE EXACT REQUIREMENTS. # # [1] Please note that the JCE for Java SE, including the JCE framework, # cryptographic policy files, and standard JCE providers provided with # the Java SE, have been reviewed and approved for export as mass market # encryption item by the US Bureau of Industry and Security. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # crypto.policy=unlimited
Java 9ããåã¯ãããã§ããã
Oracle Java JDK 9ããåã¯ãOracleå®è£ ã«ãã£ãŠèš±å¯ãããŠããããã©ã«ãæå·åŒ·åºŠã¯ã匷åã ãå¶éä»ãã§ãã(ããšãã°ã128ãããã«å¶éãããAESããŒ)ããã®å¶éããªããã«ã¯ã管çè ããç¡å¶é匷床ã®ç®¡èœããªã·ãŒã»ãã¡ã€ã«ã®ãã³ãã«ãå¥ã«ããŠã³ããŒãããŠã€ã³ã¹ããŒã«ããŸãã
ã§ã¯ãã©ãããŠå¶éãããŠããããšãããšãããã§ãã
ãããŸã§ã©ããã管çè ããã³ãŠãŒã¶ãŒã¯ãèªåã®å°ççãªå Žæã«å¿ãããã¹ãŠã®èŒžå ¥/茞åºã¬ã€ãã©ã€ã³ã«åŸãå¿ èŠããããŸãã
ãããç解ããã«ã¯EARïŒExport Administration RegulationsïŒãšããç±³åœèŒžåºèŠåããã®äžã®åç®ãšåœã®ãããã³ã°ãèªã¿è§£ããŠãã
å¿
èŠãããã®ã§ããâŠã
Commerce Control List Overview and the Country Chart Supplement No. 1 to Part 738 page
Commerce Control List Supplement No. 1 to Part 774
éäžã§è«ŠããŸããâŠãæ¥æ¬ã§ã¯OKãªã¯ããªã®ã§ãä»åã¯ãã®ãŸãŸäœ¿ã£ãŠã¿ãŸãã
ç§å¯éµã192ãããã«ãã
ç§å¯éµã®é·ããå€ãããšãã£ãŠããéµãšããŠçšæããããŒã¿ã®é·ããå€ããã°ããã®ã§ãããŸãã¯192ãããã®éµã«ããŸãã
AES/ECB/PKCS5Padding
ã®å Žåãç§å¯éµã¯èªåã§çšæãã圢ã«ããŸããã
@Test public void ecbUsing192BitSecretKey() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 24; // 192 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey); byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey); byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
ä»åã¯ãSecureRandom
ã§çšæããéµã24ãã€ãïŒ192ãããïŒã«ããŠããŸãã
// User Defined SecretKey int keySize = 24; // 192 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes);
ãã€ã³ãã¯ããã ãã§ãã
AES/CBC/PKCS5Padding
ã®å ŽåãIVã¯èªåã§çšæããŠããŸãã
@Test public void cbcUsing192BitSecretKey() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 24; // 192 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // Initial Vector int blockSize = 16; byte[] ivBytes = new byte[blockSize]; random.nextBytes(ivBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec encryptIv = new IvParameterSpec(ivBytes); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey, encryptIv); // using iv byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec decryptIv = new IvParameterSpec(ivBytes); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey, decryptIv); // using iv byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
ç§å¯éµã256ãããã«ãã
ç§å¯éµã256ãããã«ããŠã¿ãŸããçšæããéµã®ããŒã¿ã®ãµã€ãºãå€ããã ããªã®ã§ãã³ãŒããèŒããã ãã«ããŸãâŠã
AES/ECB/PKCS5Padding
ã®å Žåã
@Test public void ecbUsing256BitSecretKey() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 32; // 256 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey); byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey); byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
AES/CBC/PKCS5Padding
ã®å Žåã
@Test public void cbcUsing256BitSecretKey() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException { // target byte[] value = "ããã«ã¡ã¯ãäžç".getBytes(StandardCharsets.UTF_8); // User Defined SecretKey int keySize = 32; // 256 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // Initial Vector int blockSize = 16; byte[] ivBytes = new byte[blockSize]; random.nextBytes(ivBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec encryptIv = new IvParameterSpec(ivBytes); encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey, encryptIv); // using iv byte[] encrypted = encryptor.doFinal(value); // decrypt Cipher decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKey decryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); IvParameterSpec decryptIv = new IvParameterSpec(ivBytes); decryptor.init(Cipher.DECRYPT_MODE, decryptSecretKey, decryptIv); // using iv byte[] decrypted = decryptor.doFinal(encrypted); // assertion assertThat(new String(decrypted, StandardCharsets.UTF_8)).isEqualTo("ããã«ã¡ã¯ãäžç"); }
å€ãªéµã®é·ãã«ããŠã¿ã
ãããããµãã«åçŽã«åãããŠãããšããäžå®ã«ãªãã®ã§ãéµã®ãµã€ãºããµããŒããããŠããªããã®ã«ãããšã©ããªããã
確èªããŠã¿ãŸããã
ECBã§éµã®é·ãã64ãã€ãïŒ512ãããïŒã«ããŠã¿ãŸãã
@Test public void invalidKeyLength() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // User Defined SecretKey int keySize = 64; // 512 bit SecureRandom random = new SecureRandom(); byte[] secretKeyBytes = new byte[keySize]; random.nextBytes(secretKeyBytes); // encrypt Cipher encryptor = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKey encryptSecretKey = new SecretKeySpec(secretKeyBytes, "AES"); assertThatThrownBy(() -> encryptor.init(Cipher.ENCRYPT_MODE, encryptSecretKey)) .isInstanceOf(InvalidKeyException.class) .hasMessage("Invalid AES key length: 64 bytes"); }
ãããšãInvalidKeyException
ãã¹ããŒãããŸãã
éµã®é·ãããã§ãã¯ããŠããã®ã¯ãããã§ããã
ãããŠã䜿ããéµã®é·ããå®çŸ©ãããŠããã®ã¯ãããã§ãã
16ãã€ãïŒ128ãããïŒã24ãã€ãïŒ192ãããïŒã32ãã€ãïŒ256ãããïŒã®3ã€ãå®çŸ©ãããŠããŸãã
ãŸãšã
Javaã§ãAESïŒECBãCBCã®ããã£ã³ã°ããã«éã£ãŠã§ããïŒãæ±ãã³ãŒããæžããŠã¿ãŸããã
æã 䜿ã£ããããæã«å®å šã«å¿ããŠããã®ã§ãã¡ã¢ãšããŠã
AESã®ãœãŒã¹ã³ãŒããèªãã ããCipher
ãŸããïŒãšãããJCAïŒã«é¢ããããã¥ã¡ã³ããèªãããæ©äŒã«ããªããŸããã