ESP8266 で RSA 暗号化の方式の一つである RSA PKCS#1 V1.5 、別名 RSAES-PKCS1-v1_5 の暗号を復号する方法です。
目次
別記事で、AES-CBC PKCS#7 Padding の暗号化・復号を ESP8266 で実現しました。
今回は、RSA 暗号化の方式の一つである RSA PKCS#1 V1.5 、別名 RSAES-PKCS1-v1_5 の暗号の復号を ESP8266 で試します。前回同様、ESP8266 の SDK に付属している BearSSL を利用して実装します。
RSA 暗号化の2つの方式
RSA アルゴリズムでの暗号化には2つの方式があります。
- RSA OAEP(RSAES-OAEP)
- RSA PKCS#1 V1.5(RSAES-PKCS1-v1_5)
後者の RSAES-PKCS1-v1_5 は古い方式とされており、前者の RSAES-OAEP 方式が推奨されています。しかしこの度、RSAES-PKCS1-v1_5 の復号を実装する機会があったので、その方法を簡単に紹介する運びとなりました。
PKCS#1 V1.5 の名が付くスキームは、他にも RSASSA-PKCS1-v1_5 や EMSA-PKCS1-v1_5 がありますが、これらは証明書の署名に関するスキームであり、今回扱う暗号化スキーム RSAES-PKCS1-v1_5 とは異なります。
RSA PKCS1 V1.5 暗号の復号
先にプログラムを示します。このプログラムは事前に公開鍵を送信したサーバーから暗号文が届き、それを秘密鍵で復号するという想定で書いています。
const char rsa_private_key[] = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
)EOF";
const char rsa_public_key[] = R"EOF(
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
)EOF";
// Input : data
uint8_t data[] = {...};
int len = sizeof(data);
// RSA PKCS#1 V1.5 Decryption
BearSSL::PrivateKey *private_key = new BearSSL::PrivateKey(rsa_private_key);
(*br_rsa_private_get_default())(data, private_key->getRSA());
int i;
for(i = 2; i < len; i++){
if(data[i] == 0) break;
}
i++;
len -= i;
uint8_t decoded_data[len];
memcpy(decoded_data, &data[i], len);
// Output : Decoded data
// return decoded_data;
プログラムの説明
鍵を PEM 形式で書きます。ESP8266 に鍵のペアを生成させるのは難しい気がするので、鍵の生成は openssl などで事前に済ませておきます。
const char rsa_private_key[] = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
)EOF";
鍵は ESP8266 Arduino ライブラリの BearSSL::PrivateKey
クラスにブチ込みます。
BearSSL::PrivateKey *private_key = new BearSSL::PrivateKey(rsa_private_key);
暗号は次で復号します。復号文は暗号を格納していた data
に書かれます。
(*br_rsa_private_get_default())(data, private_key->getRSA());
次は、PKCS#1 V1.5 Padding の処理です。復号文から元の平文を抽出します。
RSAES-PKCS1-v1_5 では、復号文は 00 02
から始まります。そして、平文は、次に 00 が現れたらその次のバイトから始まります。要するに、復号文は 00 02 <ゴミ(00を含まない)> 00 <平文>
という形式になっています。
int i;
for(i = 2; i < len; i++){
if(data[i] == 0) break;
}
i++;
len -= i;
uint8_t decoded_data[len];
memcpy(decoded_data, &data[i], len);