本記事の背景
SGXでrijndael encryptionができるみたいなのでやってみた。
インターネットの海を彷徨っても(英語でも、日本語でも)文献があまり見当たらなかったのでまとめた。
本記事の対象
- Intel SGXについて知っていること。
- rijndael(AES)暗号化について知ってること。
- Enclave.edl/Enclave.cpp/App.cppで何をやっているかわかること。
サンプルコード
sgx_rijndael128GCM_decrypt/encrypt
をやってみるサンプルです。
Enclave.edl
user_checkが大事なようです。まず最も大事なことは、ポインターで渡そうがなんだろうが、enclave内ではすべて値コピーされます。なので、参照渡しは不可能です。ではどうやって書き換えるかですが、[out]というのを変数の前につけてあげます。[out]をつけると、非Enclave領域に値コピーして書き込んでくれます。このとき、非Enclave側で確保した配列の大きさをsizeで指定してやるのがよさそうです。
public sgx_status_t enclave_enc([in, size = plain_len] unsigned char * plain,
size_t plain_len, [out, size=cipher_len] unsigned char * cipher,
size_t cipher_len, [in, out] sgx_aes_gcm_128bit_tag_t * tag);
public sgx_status_t enclave_dec(
[in, size = cipher_len] unsigned char *cipher, size_t cipher_len,
[out, size=plain_len] char *plain, size_t plain_len, [in] sgx_aes_gcm_128bit_tag_t *tag);
Enclave.cpp
ポイントはaadにNULLを、ivに12byteの配列を入れること。本サンプルでは定数を用いていますが、ivは必ずランダムに生成してください。
sgx_status_t enclave_enc(unsigned char * plain, size_t plain_len,
unsigned char * cipher, size_t cipher_len, sgx_aes_gcm_128bit_tag_t * tag)
{
sgx_status_t ret;
sgx_key_128bit_t mk = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
uint8_t iv[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // 96bit(12byte)?
ret = sgx_rijndael128GCM_encrypt(&mk, plain, plain_len, cipher, iv, 12, NULL, 0, tag);
return ret;
}
sgx_status_t enclave_dec(unsigned char * cipher, size_t cipher_len,
char * plain, size_t plain_len, sgx_aes_gcm_128bit_tag_t * tag)
{
sgx_key_128bit_t mk = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
sgx_status_t ret;
uint8_t iv[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // 96bit(12byte)?
ret = sgx_rijndael128GCM_decrypt(&mk, cipher, cipher_len, (unsigned char *)plain, iv, 12, NULL, 0, tag);
return ret;
}
App.cpp
まず暗号化から。ポイントは、App側で領域確保を行うこと。[out, size]設定により、Enclave側でも自動で領域の確保を行ってくれる。暗号化後の文字列のサイズはstrlenで取得できる。
sgx_status_t status, sgxrv;
sgx_aes_gcm_128bit_tag_t tag;
char text[32] = "fizzbuzz";
unsigned char cipher[60] = {};
status = enclave_enc(eid, &sgxrv, (unsigned char*)text, strlen(text), cipher, 60, &tag);
int cipher_len = strlen((char *)cipher);
続いて復号。長さは同様にstrlenで復号できるし、%s使って出力も可能。
char plain[60] = {};
status = enclave_dec(eid, &sgxrv, cipher, cipher_len, plain, 60, &tag);
int plain_len = strlen(plain);
printf("%s\n", plain);