2024年12月11日水曜日

aes-ccm を Java で

aesCcmJava.md

先日作ったOpenSSLでのaes-ccmの暗号化結果が正しいのか?OpenSSLで復号化して検証してもなんだかなぁ。と思ったのでJavaで検証してみた。
普通にJavaをインストールした状態のjceではaes-ccmはサポートされていない。そんな時はBouncyCastleだ。

package aesccm; import java.util.HexFormat; import java.crypto.Cipher; import java.crypto.IvParameterSpec; import java.crypto.SecretKeySpec; import org.bouncycastle.jcajce.spec.AEADParameterSpec; class App { private static byte[] keyBytes = {(略)}; private static byte[] ivBytes = {(略)}; private static byte[] plainDataBytes = {(略)}; private static byte[] encryptDataBytes = {(略)}; private static byte[] encryptDataWithTagBytes = {(略)}; public static void main( String[] args) { try { java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider()); } catch( Exception e) { e.printStackTrace(); return; } var hex = HexFormat.ofDelimiter( ", ").withPrefix( "0x"); var encryptData = encrypt( plainDataBytes); System.out.println( encryptData); var encryptFreeTagSizeData = encryptFreeTagSize( plainDataBytes); System.out.println( encryptFreeTagSizeData); var decryptData = decrypt( encryptDataBytes); System.out.println( decryptData); var decryptFreeTagSizeData = decryptFreeTagSize( encryptDataWithTagBytes); System.out.println( decryptFreeTagSizeData); } public static byte[] encrypt( byte[] dataBytes) { // rfc 規定の方法で暗号化 Tag は暗号化データと連結される try{ var ciper = Cipher.getInstance( "AES/CCM/NoPadding"); var key = new SecretKeySpec( keyBytes, "AES"); var iv = new IvParameterSpec( ivBytes); cipher.init( Cipher.ENCRYPT_MODE, key, iv); return cipher.doFinal( dataBytes); } catch( Exception e) { e.printStackTrace(); } return new byte[0]; } public static byte[] encryptFreeTagSize( byte[] dataBytes) { // Tag のサイズを指定した暗号化 try{ var ciper = Cipher.getInstance( "AES/CCM/NoPadding"); var key = new SecretKeySpec( keyBytes, "AES"); // Tag のサイズは "bit"数 で指定する。ゼロを指定するとタグは付かない var aeadParameterSpec = new AEADParameterSpec( ivBytes, 32); cipher.init( Cipher.ENCRYPT_MODE, key, aeadParameterSpec); return cipher.doFinal( dataBytes); } catch( Exception e) { e.printStackTrace(); } return new byte[0]; } public static byte[] decrypt( byte[] dataBytes) { // rfc 規定の方法で暗号化 されたデータの復号化 try{ var ciper = Cipher.getInstance( "AES/CCM/NoPadding"); var key = new SecretKeySpec( keyBytes, "AES"); var iv = new IvParameterSpec( ivBytes); cipher.init( Cipher.DECRYPT_MODE, key, iv); return cipher.doFinal( dataBytes); } catch( Exception e) { e.printStackTrace(); } return new byte[0]; } public static byte[] decryptFreeTagSize( byte[] dataBytes) { // rfc 規定の方法で暗号化 されたデータの復号化 try{ var ciper = Cipher.getInstance( "AES/CCM/NoPadding"); var key = new SecretKeySpec( keyBytes, "AES"); // Tag のサイズは "bit"数 で指定する。ゼロを指定するとタグの検証は行われない var aeadParameterSpec = new AEADParameterSpec( ivBytes, 32); cipher.init( Cipher.DECRYPT_MODE, key, aeadParameterSpec); return cipher.doFinal( dataBytes); } catch( Exception e) { e.printStackTrace(); } return new byte[0]; } }

2024年12月3日火曜日

aes-ccm を OpenSSL で

aes-ccm を OpenSSL で

発端

aes-ccm を OpenSSL で処理しようにもコマンドでは対応していない。
OpenSSLのライブラリを使ってプログラムで処理するしかない。

どうすればいい?

OpenSSL WikiのEVP Authenticated Encryption and Decryptionを参考にして検証してみた。(aad は面倒なのでなくした)

int ccm_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext, unsigned char *tag) { EVP_CIPHER_CTX *ctx; int len; int ciphertext_len; /* EVP_CIPHER_CTX の確保 */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* aes-256-ccm 暗号化モードで初期化(復号化の場合はEVP_DecryptInit_ex) */ if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL)) handleErrors(); /* IV の長さを設定 */ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, 7, NULL)) handleErrors(); /* Tag の長さを設定 */ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, NULL); /* key と IV の値を設定 */ if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors(); /* 暗号化対象データの長さを設定 */ if(1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, plaintext_len)) handleErrors(); /* 暗号化対象のデータ、暗号化データの出力先、暗号化データサイズの出力先を渡して 操作の実行 /* if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) handleErrors(); ciphertext_len = len; /* 操作の完了。通常、暗号化データはこの時点で書き込まれるが CCM の場合は書き込まれない。 */ if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors(); ciphertext_len += len; /* Tag の取得 */ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 14, tag)) handleErrors(); /* 終了処理 */ EVP_CIPHER_CTX_free(ctx); return ciphertext_len; }