システムのセキュリティについて考慮されることが多くなってきた昨今、SalesforceやJavaで構築するシステムでも、情報を暗号化して運用することが求められるようになっています。
特に、パスワードは暗号化して保持したり、さらにはインターネット上でやり取りする情報についても暗号化して送信し、受け取り側で復号することシーンもあることでしょう。
今回は、2回にわたって、JavaやSalesforceで可逆的な暗号化を実現する方法をご紹介します。
初回の今回は、Salesforceでの可逆暗号化のしくみ、特にApexコードでの実現方法を見てみることにします。
ゴールは、
- あるキーワードを元に、PrivateKeyを生成する。
- そのキーを元に、テキストを暗号化。
- その暗号化されたテキストを別なところに送る。(PrivateKeyは別途送っておく)
- 受け取った別なところで、PrivateKeyを元に、テキストを複合化。
ということにします。
ただし、PrivateKeyを送っておいても、Salesforce上に保持してApexで読み込むのは手間なので、生成したPrivateKeyをBase64でテキストにして別途送ることにします。
こうすることで、読み込み部分こコーディングがかなりシンプルになります。
さて、Apexで利用できる暗号化のクラスには「Crypto Class」というものがあります。
詳しいAPI仕様書は下記ページを確認してみてください。
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_crypto.htm
暗号化する
早速暗号化するコードを書いてみましょう。
Blob MyPrivateKey = Crypto.generateAesKey(128); System.debug(MyPrivateKey.size()); System.assertEquals(16, MyPrivateKey.size()); String b64formattedKeyStr=EncodingUtil.base64Encode(MyPrivateKey); system.debug('★This is b64formattedKeyStr= '+ b64formattedKeyStr); Blob blobData = Blob.valueOf('sample Text'); Blob encryptedData = Crypto.encryptWithManagedIV('AES128',MyPrivateKey,blobData); String EncryptedDataString = EncodingUtil.base64Encode(encryptedData); system.debug('★This is encrypted data String= '+ EncryptedDataString);
解説すると、
Blob MyPrivateKey = Crypto.generateAesKey(128);
Blob型のPrivateKeyを作ります。SalesforceのCryptoで利用できる暗号化方式は、AES128,AES192,AES256ですが、引数が128なので、AES128で秘密鍵ができます。
これは、16Byteです。(このバイト数は後で出てきますが結構重要です。)
ただし、この鍵はgenerateAesKeyが呼ばれるたびに変わるので、ここで生成した鍵を保持しておく必要があります。
Blob型だと扱いにくいので、次のやり方でテキスト型にしてしまいます。
String b64formattedKeyStr=EncodingUtil.base64Encode(MyPrivateKey);
EncodingUtilのbase64Encodeメソッドで生成したPrivateKeyをBase64化します。これにより、テキストで簡単に鍵をやり取りできます。
このコードの下にログを仕込んでありますが、上記コードを動かすと、
xx:xx:xx:xxx USER_DEBUG [x]|DEBUG|★This is b64formattedKeyStr= XX71Fq***6p/99dWGfOpXX==
のようにログが吐かれると思います。
この「XX71Fq***6p/99dWGfOpXX==」がBase64化されたテキスト型の秘密鍵なので、これを別なシステムに送って、そこでBlob型へ逆Base64化すれば元の鍵になるというわけです。
Blob encryptedData = Crypto.encryptWithManagedIV(‘AES128’,MyPrivateKey,blobData);
実際に生成した秘密鍵を使ってテキストを暗号化している箇所になります。
Cryptoクラスにはもうひとつ「encrypt」というメソッドがありますが、そっちは初期化ベクトルをメソッドに与える必要があります。
encryptWithManagedIVはそれをSalesforceで与えてくれるので、少し引数がシンプルになります。
String EncryptedDataString = EncodingUtil.base64Encode(encryptedData);
秘密鍵を使って暗号化されたテキストもBase64化してみます。すると、直下のログで以下のように出力されると思います。(下記は適当にマスクしています。)
15:41:18:086 USER_DEBUG [11]|DEBUG|★This is encrypted data String= sKXityHtqPxWFw***B0GXGXS***lXr6ewX1QAXcdS8=
復号する
Blob DecMyPrivateKey = EncodingUtil.base64Decode('Base64化されたPrivateKey文字列'); Blob DecEncryptedData = EncodingUtil.base64Decode('sKWityHtqPxWFwcgtB0GWGIScoxdlXr6ewZ1QAPcdS8='); Blob decryptedData = Crypto.decryptWithManagedIV('AES128',DecMyPrivateKey,DecEncryptedData); String decryptedDataString = EncodingUtil.base64Encode(decryptedData); system.debug('★★This is decrypted Data ='+ decryptedDataString + '&' +decryptedData.toString());
- 上記で暗号化された文字列を、別のSalesforce組織で復号化する
- 他の言語、システムで暗号化された文字列をSalesforce組織で復号化する
といったことを実現します。
基本的には暗号化の時を逆のことをするだけです。
秘密鍵として、「Base64化されたPrivateKey文字列」つまり「XX71Fq***6p/99dWGfOpXX==」を指定するところがキモですね。
他の言語で暗号化されたテキストであっても、暗号化された方式が同じであれば問題なく複合できます。
他の言語での暗号化の例として、Javaを記事にしましたので、ご参照ください。