2016-08-10 30 views
1

異なるシステム間でのクロスコンポーネント暗号化を試みています。現在、私は実際に出力を一致させることはできません。 私はC言語用のopenssl/aes/hライブラリと、Java/Scala用のjavax.cryptoを使用しています。 私はCシステムのコードを変更することに柔軟性がないので、Java/Scalaコードを変更する必要があります。AES暗号化クロスコンポーネントJava/ScalaとC

#include <string.h> 
#include <openssl/aes.h> 

char key[] = "aaaaaaaaaaaaaaaa"; 

int main(){ 
unsigned char text[]="hello"; 
unsigned char enc_out[80]; 
unsigned char dec_out[80]; 

AES_KEY enc_key, dec_key; 

AES_set_encrypt_key(key, 128, &enc_key); 
AES_encrypt(text, enc_out, &enc_key); 
return 0 
} 

Cコードは、おおよそ必要なときに(鍵が128ビットでない場合)、0でパディングがある以外はAES_set_encrypt_keyとAES_ENCRYPTコールthat.Usingように見えます。この単純な例では、パディングは重要です。 BASE64

にCコードがで "XaiMOCo7KteRUkejpd8JLA =="

を与えるキーを使用して

def aes_encrypt(value: String, k: String): Array[Byte] = { 
    val cipher = Cipher.getInstance("AES") 
    val key = Arrays.copyOf(k.getBytes("UTF-8"), 16) 
    val secretKey: SecretKeySpec = new SecretKeySpec(key, 0, key.length, "AES") 
    cipher.init(Cipher.ENCRYPT_MODE, secretKey) 
    cipher.doFinal(value.getBytes("UTF-8"), 0, value.getBytes("UTF-8").length) 
    } 

"aaaaaaaaaaaaaaaa" およびメッセージ "ハロー"、:私はScalaのコードで

Scala/Java "7GHRfFgKVdaAiwti36tqDQ =="

私は出力を一致させようとしていますが、できませんでした。 私はScalaコードに対して別のアルゴリズムを試しましたが、どのようにC出力にマッチさせるべきかわかりません。

私はAES_set_encrypt_keyとAES_encrypt呼び出しのドキュメントを調べようとしましたが、あまりにも多くを掘り下げることはできませんでした。私はevp_encryptionコールなどのOpenSSLライブラリからより優れたユーザーフレンドリーなコールがあることを知っているが、私はAES_set_encrypt_keyとAES_ENCRYPT

+1

実際には 'EVP_ *'関数を使うべきです。なぜなら、デフォルトではパディングが含まれているからです。 aes.hの関数はむしろ基本的なものであり、まったく使用されていないはずです。 –

+1

あなたは 'AES_encrypt'とフレンドを使うべきではありません。これはソフトウェアのみの実装なので、AES-NIなどのハードウェアサポートは受けられません。あなたは 'EVP_ *'関数を使用していなければなりません。 OpenSSL wikiの[EVP Symmetric Encryption and Decryption](http://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption)を参照してください。実際には、機密性と信頼性の両方を提供するため、おそらく認証された暗号化を使用するべきです。 OpenSSL wikiの[EVP Authenticated Encryption and Decryption](http://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption)を参照してください。 – jww

答えて

1

私は出力に一致するようにしようとしていますから逃れることはできませんが、私はやることができていませんそれ...

OpenSSLでは、あなたはECBモードで暗号を操作しており、あなたはパディングを担当しています。私は、OpenSSLが6文字(hello\0)と10個のガベージ文字からなる16バイトを暗号化していると信じています。

Javaの場合は、AES/ECB/PKCS5Paddingの暗号を使用していると思います。 value: Stringは、PKCSパディングを使用して無条件にパディングされます。パディングは、OpenSSLが16のままである間に、16バイトの平文が32バイトの暗号文に展開されることを意味します。

このような場合は、テストベクトルに戻ってどの実装が分岐しているかを確認することができます。 AESの場合、しばしばBrian Gladmanのベクトルを使用します。


私はAES_set_encrypt_keyとAES_ENCRYPT呼び出しのドキュメントを調べることを試みたが、私はそれの外にあまり掘ることができませんでした。私はevp_encryptionコールなどのOpenSSLライブラリからより優れたユーザーフレンドリーなコールがあることを知っているが、私は、彼らはあなたがそれらを使用したくないので、OpenSSLはそれらを文書化していない離れAES_set_encrypt_keyとAES_ENCRYPTから

取得することはできません。 AES_encryptとお友達と一緒にご滞在の場合は、ソフトウェアのみの実装と結婚しています。また、EVPインターフェイスがあなたのためにそれを処理するので、エンディアン問題を時々被るでしょう。最後に、ではなく、i686のAES-NIやARMv8のAESなどのハードウェアアクセラレーションを楽しむことになります。あなたはPKCSパディングとECBモードを目指してい場合


CコードがXaiMOCo7KteRUkejpd8JLA==を与え、スカラ座/ Javaの7GHRfFgKVdaAiwti36tqDQ==

関連では、スカラ/ Javaは正しいです。私は(そのStreamTransformationFilterがデフォルトでPKCSパディングを使用しています)Crypto++とScalaの/ Javaの結果を再現することができますコメント

私はAES/ECBをしようとしますから、

int main(int argc, char* argv[]) 
{ 
    byte key[] = "aaaaaaaaaaaaaaaa"; 
    ECB_Mode<AES>::Encryption enc(key, 16); 
    string result; 

    StringSource ss(string("hello"), true, 
        new StreamTransformationFilter(enc, 
         new Base64Encoder(
          new StringSink(result)))); 

    cout << result << endl; 

    return 0; 
} 

/NoPaddingとScalaで自分自身をパディングします。

Cプログラムでは、ガベージ文字を避ける必要があります。たぶん、次のようなものを使用すると、JavaのPKCS #7 padding0x0bは適用され11回)と一致するのに役立ちます:

unsigned char text[] = "hello\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; 

をここでPKCS #7 paddingで埋め長い文字列(0x06が適用6回)です:

unsigned char text[] = "hellohello\x06\x06\x06\x06\x06\x06"; 

が文字列の場合長さが16である場合、0x10を16回適用します。 ECBを使用する場合は


、それはIVベクトルを必要としていますか?

番号ECBモードはIVを必要としません。それはキーの下で16バイトのブロックを暗号化します(それ以上は何もありません)。

+0

情報ありがとうございます。私はAES/ECB/NoPaddingをやろうとし、Scalaではパディングを自分自身でやっていきます。 ECBを使用する場合、IVベクトルが必要ですか?もしあれば、デフォルトのopenssl IVベクタは何ですか? – Andrew

+0

@Andrew - プロバイダのデフォルトのAES実装が「AES/ECB/PKCS5Padding」であることを確認してください。 [Javaのデフォルトの暗号化/ AESの動作](http://stackoverflow.com/q/6258047)も参照してください。 – jww

+0

ありがとうございました! 'Cipher.getInstance(" AES/ECB/NoPadding ")'に変更し、16の倍数になるまでメッセージバイト配列を0でパディングしました。 'Arrays.copyOf(value.getBytes(" UTF-8 ")、paddedLength)それは私に同じ結果をもたらしました。私はそれを0で埋めても、それを '0x0b' – Andrew