diff --git a/dub.sdl b/dub.sdl index e372e5b..884a00e 100644 --- a/dub.sdl +++ b/dub.sdl @@ -10,7 +10,8 @@ subPackage "linux" subPackage "thirdparty/libdparse" subPackage "thirdparty/json" subPackage "thirdparty/vibe-d" +subPackage "thirdparty/openssl" dependency "dateparser" version="~>3.0.4" -buildOptions "coverage" \ No newline at end of file +buildOptions "coverage" diff --git a/thirdparty/openssl/dub.sdl b/thirdparty/openssl/dub.sdl new file mode 100644 index 0000000..97e422b --- /dev/null +++ b/thirdparty/openssl/dub.sdl @@ -0,0 +1,12 @@ +name "openssl_usage" +description "A minimal D application." +authors "SHOO" +copyright "Copyright © 2021, SHOO" +license "public domain" +# WindowsでOpenSSLを使うにはコンパイル済みのバイナリ(DLL+lib)が必要。 +# 自前で用意するのは手間なので、openssl-staticで用意されているものを使用する。 +# openssl-staticは内部でDeimosのopensslに依存しているので、 +# 改めてDeimosのopensslをdubのプロジェクト設定に追加する必要はない。 +dependency "openssl-static" version="~>1.0.2+3.0.8" +libs "Advapi32" platform="windows" +libs "User32" platform="windows" diff --git a/thirdparty/openssl/source/openssl_usage/example.d b/thirdparty/openssl/source/openssl_usage/example.d new file mode 100644 index 0000000..c0e7fd1 --- /dev/null +++ b/thirdparty/openssl/source/openssl_usage/example.d @@ -0,0 +1,108 @@ +/++ +OpenSSLの使用例 + +OpenSSLはベースがCの暗号化ライブラリです。インターフェースもそのままC言語のAPIを利用します。 $(BR) +[Deimos](https://github.com/D-Programming-Deimos)という公式のC言語のバインディングプロジェクトがあり、OpenSSLもその対象になっています。 + +OpenSSLのライセンスはバージョン3.0.0未満の場合、OpenSSL LicenseとSSLeay Licenseの両方のライセンス下で公開されています。3.0.0以降の場合はApache License Version 2.0のライセンスです。$(BR) +ここで紹介するDeimos版の対応バージョンは現在3.0.0未満ですので、OpenSSL LicenseとSSLeay Licenseということになります。 + +## ドキュメント + - 公式サイト: https://www.openssl.org + - APIドキュメント: https://www.openssl.org/docs/man1.1.1/man7/ + - リポジトリ(Deimos): https://github.com/D-Programming-Deimos/openssl + - dubパッケージ(Deimos): https://code.dlang.org/packages/openssl + +Source: $(LINK_TO_SRC thirdparty/openssl/source/openssl_usage/_example.d) ++/ +module openssl_usage.example; + + +/++ +AES-128-CBCによる共通鍵暗号化/復号の例です。 + +See_Also: + - https://www.openssl.org/docs/man1.1.1/man3/EVP_CIPHER_CTX_new.html + - https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57Pt3r1.pdf P13 + - https://www.ipa.go.jp/security/ipg/documents/ipa-cryptrec-gl-3001-3.0.1.pdf P26, P37 ++/ +unittest +{ + import std.exception: enforce, assumeUnique; + import deimos.openssl.evp; + + // 暗号化 + immutable(ubyte)[] encryptAES128(in ubyte[] src, in ubyte[128/8] key, in ubyte[16] iv) + { + // 暗号化のコンテキスト作成・破棄 + auto encctx = EVP_CIPHER_CTX_new().enforce("Cannot cretae OpenSSL cipher context."); + scope (exit) + encctx.EVP_CIPHER_CTX_free(); + + // 初期化 + encctx.EVP_EncryptInit_ex(EVP_aes_128_cbc(), null, key.ptr, iv.ptr) + .enforce("Cannot initialize OpenSSL cipher context."); + + // 暗号化されたデータの格納先として、十分な量のバッファを用意。 + // 暗号化のロジックによって異なる。 + // AES128だったら元のデータよりブロックサイズ分の16バイト大きければ十分格納できる。 + ubyte[] encrypted = new ubyte[src.length + 16]; + + // 暗号化 + // ここでは一回で暗号化を行っているが、分割することもできる。 + int encryptedLen; + int padLen; + encctx.EVP_EncryptUpdate(encrypted.ptr, &encryptedLen, src.ptr, cast(int)src.length) + .enforce("Cannot encrypt update OpenSSL cipher context."); + // 暗号化完了 + encctx.EVP_EncryptFinal_ex(encrypted.ptr + encryptedLen, &padLen) + .enforce("Cannot finalize OpenSSL cipher context."); + + return encrypted[0 .. encryptedLen + padLen].assumeUnique(); + } + + // 復号 + immutable(ubyte)[] decryptAES128(in ubyte[] src, in ubyte[128/8] key, in ubyte[16] iv) + { + // 暗号化のコンテキスト作成・破棄 + auto decctx = EVP_CIPHER_CTX_new().enforce("Cannot cretae OpenSSL cipher context."); + scope (exit) + decctx.EVP_CIPHER_CTX_free(); + + // 初期化・終了処理 + decctx.EVP_DecryptInit_ex(EVP_aes_128_cbc(), null, key.ptr, iv.ptr) + .enforce("Cannot initialize OpenSSL cipher context."); + + // 復号されたデータの格納先として、十分な量のバッファを用意。 + // 暗号化のロジックによって異なる。 + // AES128だったら元のデータよりブロックサイズ分の16バイト大きければ十分格納できる。 + ubyte[] decrypted = new ubyte[src.length + 16]; + + // 復号 + // ここでは一回で復号を行っているが、分割することもできる。 + int decryptedLen; + int padLen; + decctx.EVP_DecryptUpdate(decrypted.ptr, &decryptedLen, src.ptr, cast(int)src.length) + .enforce("Cannot encrypt update OpenSSL cipher context."); + // 復号完了 + decctx.EVP_DecryptFinal_ex(decrypted.ptr + decryptedLen, &padLen) + .enforce("Cannot finalize OpenSSL cipher context."); + + return decrypted[0 .. decryptedLen + padLen].assumeUnique(); + } + + import std.conv: hexString; + import std.string: representation; + // ここでは以下のデータを暗号化して、復号します。 + static immutable ubyte[] sourceData = "あいうえお"c.representation; + // 鍵とIVには以下を使用。 + // 鍵は128bit(16バイト), IVはブロックサイズの16バイト + static immutable ubyte[128/8] key = cast(ubyte[128/8])hexString!"9F86D081884C7D659A2FEAA0C55AD015"; + static immutable ubyte[16] iv = cast(ubyte[16])hexString!"A3BF4F1B2B0B822CD15D6C15B0F00A08"; + // 暗号化 + auto encryptedData = encryptAES128(sourceData, key, iv); + // 復号 + auto decryptedData = decryptAES128(encryptedData, key, iv); + // 確認 + assert(decryptedData == sourceData); +}