スクリプト蚀語でPKCS11暗号トヌクンメカニズムを䜿甚する

「ロシアの認定x509蚌明曞を衚瀺するための英語のクロスプラットフォヌムナヌティリティ」ずいう蚘事に察する圌のコメントで、 Pasは「自分自身が数えるこずができる」PKCS11トヌクンを非垞に正確に指摘したした。 はい、トヌクンは実際には暗号化コンピュヌタヌです。 そしお、Python、Perl、Rubyなど、スクリプト蚀語でこれらのコンピュヌタヌを䜿甚したいのは自然なこずです。 蚌明曞リク゚ストを䜜成するために、ドキュメントの眲名ず暗号化のためにPythonでロシアの暗号化をサポヌトするPKCS11トヌクンの䜿甚を既に䜕らかの圢で怜蚎しおいたす 

画像

ここでは、Tcl蚀語に関する議論を続けたす。 前の蚘事で 、PKCS11トヌクン/スマヌトカヌドに保存された蚌明曞を衚瀺および怜蚌する際、 TclPKCS11バヌゞョン0.9.9パッケヌゞを䜿甚しおそれらにアクセスしたした蚌明曞。 既に述べたように、残念ながら、このパッケヌゞはRSA暗号化甚に開発され、PKCS11 v.2.20暙準を考慮に入れおいたす。 珟圚、PKCS11 v.2.40芏栌がすでに䜿甚されおおり、TK-26暗号化技術委員䌚がそれを指導し、ロシアの暗号化をサポヌトするトヌクン/スマヌトカヌドの囜内メヌカヌに掚奚事項を発行しおいたす。 そしお、これらすべおのこずで、新しいTclPKCS11パッケヌゞバヌゞョン1.0.1が登堎したした 。 RSAのすべおの暗号化むンタヌフェヌスがTclPKCS11 v.10.1パッケヌゞの新しいバヌゞョンに保存されるように、すぐに予玄したす。 パッケヌゞラむブラリはC蚀語で蚘述されおいたす。

それでは、パッケヌゞの新機胜は䜕ですか たず、接続されたトヌクンでサポヌトされおいる暗号化メカニズムのリストを取埗できるコマンドが远加されたした。

::pki::pkcs11::listmechs <handl> <slotid> 

接続されたトヌクンを含むスロットのリストを取埗する方法は、 ここに瀺されおいたす 手順-proc :: slot_with_token

 proc ::slots_with_token {handle} { set slots [pki::pkcs11::listslots $handle] # puts "Slots: $slots" array set listtok [] foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set listtok($slotid) $slotlabel } } #     parray listtok return [array get listtok] } 

簡単なスクリプトを䜜成したす。

 #!/usr/bin/tclsh lappend auto_path . package require pki::pkcs11 #      RuToken set lib "/usr/local/lib64/librtpkcs11ecp_2.0.so" <source lang="bash">set handle [pki::pkcs11::loadmodule $lib] #    #       set labslot [::slots_with_token $handle] if {[llength $labslot] == 0} { puts "     " exit } set slotid 0 set lmech [pki::pkcs11::listmechs $handle $slotid] set i 0 foreach mm $lmech { #   if {[string first "GOSTR3410" $mm] != -1} { puts -nonewline "[lindex $mm 0] " if {$i == 2} {puts "";set i 0} else { incr i} } } puts "\n" exit 

このスクリプトを䜿甚するず、RuTokenファミリトヌクンでサポヌトされおいるGOSTR3410暗号化メカニズムのリストを取埗できたす。 たず、 Pasが蚘事で曞いたように、「あらゆる皮類のEDOに愛される灯明の光」を取り䞊げたす。

 $ tclsh TEST_for_HABR.tcl listtok(0) = ruToken Lite 0 {ruToken Lite } $ 

そしお圓然、圌は蚌明されるべきGOSTメザニズムを支持しおいないこずが刀明したす。 別のトヌクンRutoken EDSを取埗したす。

 $ tclsh TEST_for_HABR.tcl listtok(0) = ruToken ECP } 0 {ruToken ECP } CKM_GOSTR3410_KEY_PAIR_GEN CKM_GOSTR3410 CKM_GOSTR3410_DERIVE CKM_GOSTR3410_WITH_GOSTR3411 $ 

はい、このトヌクンはロシアの暗号化をサポヌトしおいたすが、GOST R 34.10-2001の眲名のみを䜿甚しおいたす 。これはほずんど䜿甚されおいたせん 。 しかし、Rutoken EDS-2.0トヌクンを䜿甚するず、すべおが正垞になり、キヌ256および512ビット長のGOST R 34.10-2012がサポヌトされたす。

 $ tclsh TEST_for_HABR.tcl listtok(0) = RuTokenECP20 0 {RuTokenECP20 } CKM_GOSTR3410_KEY_PAIR_GEN CKM_GOSTR3410 CKM_GOSTR3410_DERIVE CKM_GOSTR3410_512_KEY_PAIR_GEN CKM_GOSTR3410_512 CKM_GOSTR3410_12_DERIVE CKM_GOSTR3410_WITH_GOSTR3411 CKM_GOSTR3410_WITH_GOSTR3411_12_256 CKM_GOS TR3410_WITH_GOSTR3411_12_512 $ 

グラスホッパヌやマグマの暗号化アルゎリズムを含むロシアの暗号化を1぀たたは別のトヌクンでサポヌトするこずに぀いお話し合った堎合、゜フトりェアずクラりドトヌクンで最も完党にサポヌトされたす。

 $ tclsh TEST_for_HABR.tcl listtok(0) = LS11SW2016_LIN_64 0 {LS11SW2016_LIN_64 } 

メカニズムのリスト
CKM_GOSTR3410_KEY_PAIR_GEN
CKM_GOSTR3410_512_KEY_PAIR_GEN
CKM_GOSTR3410
CKM_GOSTR3410_512
CKM_GOSTR3410_WITH_GOSTR3411
CKM_GOSTR3410_WITH_GOSTR3411_12_256
CKM_GOSTR3410_WITH_GOSTR3411_12_512
CKM_GOSTR3410_DERIVE
CKM_GOSTR3410_12_DERIVE
CKM_GOSR3410_2012_VKO_256
CKM_GOSR3410_2012_VKO_512
CKM_KDF_4357
CKM_KDF_GOSTR3411_2012_256
CKM_KDF_TREE_GOSTR3411_2012_256
CKM_GOSTR3410_KEY_WRAP
CKM_GOSTR3410_PUBLIC_KEY_DERIVE
CKM_LISSI_GOSTR3410_PUBLIC_KEY_DERIVE
CKM_GOST_GENERIC_SECRET_KEY_GEN
CKM_GOST_CIPHER_KEY_GEN
CKM_GOST_CIPHER_ECB
CKM_GOST_CIPHER_CBC
CKM_GOST_CIPHER_CTR
CKM_GOST_CIPHER_OFB
CKM_GOST_CIPHER_CFB
CKM_GOST_CIPHER_OMAC
CKM_GOST_CIPHER_KEY_WRAP
CKM_GOST_CIPHER_ACPKM_CTR
CKM_GOST_CIPHER_ACPKM_OMAC
CKM_GOST28147_KEY_GEN
CKM_GOST28147
CKM_GOST28147_KEY_WRAP
CKM_GOST28147_PKCS8_KEY_WRAP
CKM_GOST_CIPHER_PKCS8_KEY_WRAP
CKM_GOST28147_ECB
CKM_GOST28147_CNT
CKM_GOST28147_MAC
CKM_KUZNYECHIK_KEY_GEN
CKM_KUZNYECHIK_ECB
CKM_KUZNYECHIK_CBC
CKM_KUZNYECHIK_CTR
CKM_KUZNYECHIK_OFB
CKM_KUZNYECHIK_CFB
CKM_KUZNYECHIK_OMAC
CKM_KUZNYECHIK_KEY_WRAP
CKM_KUZNYECHIK_ACPKM_CTR
CKM_KUZNYECHIK_ACPKM_OMAC
CKM_MAGMA_KEY_GEN
CKM_MAGMA_ECB
CKM_MAGMA_CBC
CKM_MAGMA_CTR
CKM_MAGMA_OFB
CKM_MAGMA_CFB
CKM_MAGMA_OMAC
CKM_MAGMA_KEY_WRAP
CKM_MAGMA_ACPKM_CTR
CKM_MAGMA_ACPKM_OMAC
CKM_GOSTR3411
CKM_GOSTR3411_12_256
CKM_GOSTR3411_12_512
CKM_GOSTR3411_HMAC
CKM_GOSTR3411_12_256_HMAC
CKM_GOSTR3411_12_512_HMAC
CKM_PKCS5_PBKD2
CKM_PBA_GOSTR3411_WITH_GOSTR3411_HMAC
CKM_TLS_GOST_KEY_AND_MAC_DERIVE
CKM_TLS_GOST_PRE_MASTER_KEY_GEN
CKM_TLS_GOST_MASTER_KEY_DERIVE
CKM_TLS_GOST_PRF
CKM_TLS_GOST_PRF_2012_256
CKM_TLS_GOST_PRF_2012_512
CKM_TLS12_MASTER_KEY_DERIVE
CKM_TLS12_KEY_AND_MAC_DERIVE
CKM_TLS_MAC
CKM_TLS_KDF
CKM_TLS_TREE_GOSTR3411_2012_256
CKM_EXTRACT_KEY_FROM_KEY
CKM_SHA_1
CKM_MD5

 $ 

パッケヌゞに远加される次の新機胜に進みたす。

 set listcertsder [pki::pkcs11::listcertsder $handle $slotid] 

この関数は、トヌクンなしで保存された蚌明曞のリストを返したす。 問題は自然に発生したすが、既存の関数pki :: pkcs11 :: listcertsずどう違うのですか

たず、新しい関数は:: pkiパッケヌゞを䜿甚したせん。 返される芁玠の1぀は、完党な蚌明曞を含むcert_der芁玠です。 これは、たずえば、蚌明曞を゚クスポヌトしたり、指王を受け取ったりする堎合に䟿利です。 以前は 、TBS蚌明曞ずその眲名から完党な蚌明曞を収集する必芁がありたした。 1぀の蚌明曞の内容を印刷するず、各蚌明曞の返品アむテムの完党なリストが明確に衚瀺されたす。

 . . . array set derc [[pki::pkcs11::listcertsder $handle $slotid] 0] parray derc derc(cert_der) = 3082064a 
 derc(pkcs11_handle) = pkcsmod0 derc(pkcs11_id) = 5882d64386211cf3a8367d2f87659f9330e5605d derc(pkcs11_label) = Thenderbird-60   derc(pkcs11_slotid) = 0 derc(type) = pkcs11 . . . 

pkcs11_id芁玠には、公開キヌからのSHA-1ハッシュの倀である属性CKA_IDが栌玍されたす。 cert_der゚レメントはCKA_VALUE蚌明曞、pkcs11_labelはCKA_LABELです。

pkcs11_id芁玠PKCS11暙準の甚語ではCKA_IDは、pkcs11_handleラむブラリずずもに、pkcs11_slotidトヌクンを持぀スロット識別子は、トヌクンに栌玍されたキヌおよび蚌明曞にアクセスするためのキヌ芁玠です 。

そのため、蚌明曞たたはキヌのラベルpkcs11_labelを倉曎する堎合は、次の圢匏のコマンドを実行したす。

 pki::pkcs11::rname <cert|key|all> <  > 

蚌明曞たたはキヌをトヌクンから削陀するには、次の圢匏のコマンドが実行されたす。

 pki::pkcs11::delete <cert|key|all> <  > 

キヌ芁玠のリストは、次のように圢成できたす。

 set listparam {} lappend listparam pkcs11_handle lappend listparam $handle lappend listparam pkcs11_slotid lappend listparam $pkcs11_slotid lappend listparam pkcs11_id lappend listparam $pkcs11_id 

など
この堎合の関数呌び出しは次のようになりたす蚌明曞ずそれに関連するキヌを削陀したす

 pki::pkcs11::delete all $listparam 

読者はおそらく、このリストを蟞曞蟞曞ずしお配眮できるこずをすでに掚枬しおいるでしょう。

 set listparam [dict create pkcs11_handle $pkcs11_handle] dict set listparam pkcs11_slotid $pkcs11_slotid) dict set listparam pkcs11_id $pkcs11_id 

他の方法、たずえば配列配列がありたす。

繰り返したすが、pkcs11_handleおよびpkcs11_slotid芁玠は、接続されたトヌクンを䞀意に識別するキヌ芁玠のリストに垞に存圚する必芁があるこずに泚意しおください。 残りの構成は、特定の機胜によっお決たりたす。

次の関数を䜿甚しお、トヌクンに蚌明曞をむンストヌルしたす。

 set pkcs11_id_cert [::pki::pkcs11::importcert <cert_der_hex> <  > 

この関数は、倀CKA_IDを16進数で返したす。 鍵パラメヌタヌのリストは、蚌明曞が配眮されるトヌクンを決定したす。

 {pkcs11_handle <handle> pkcs11_slotid <slotid>} 

次はハッシュ蚈算です。 今日のロシアの暗号では、3皮類のハッシュ関数が䜿甚されおいたす。
-GOST R 34.11-94
-GOST R 34.11-2012、ハッシュ倀256ビットstribog256
-GOST R 34 .11-2012、ハッシュ倀512ビットstribog512
どのハッシュがトヌクンをサポヌトするかを決定するために、関数pki :: pkcs11 :: listmechsがありたす。

ハッシュ蚈算関数の圢匏は次のずおりです。

 set <> [pki::pkcs11::digest <gostr3411|stribog256|stribog512|sha1> <  > <  >] 

蚈算の蚈算結果は16進圢匏で衚瀺されるこずに泚意しおください。
 . . . set listparam [dict create pkcs11_handle $pkcs11_handle] dict set listparam pkcs11_slotid $pkcs11_slotid set res_hex [pki::pkcs11::digest stribog256 0123456789 $listparam] puts $res_hex 086f2776f33aae96b9a616416b9d1fe9a049951d766709dbe00888852c9cc021 

怜蚌のために、ロシアの暗号化をサポヌトするopensslを䜿甚しおみたしょう。

 $ echo -n "0123456789"|/usr/local/lirssl_csp_64/bin/lirssl_s tatic dgst -md_gost12_256 (stdin)= 086f2776f33aae96b9a616416b9d1fe9a0499 51d766709dbe00888852c9 cc021 $ 

ご芧のずおり、結果は同じです。

蚌明曞、倱効した蚌明曞のリスト、たたは圢匏の眲名されたドキュメントのいずれであっおも、電子眲名を怜蚌するには、眲名怜蚌機胜のみが必芁です。

 set result [pki::pkcs11::verify < > < > <  >]] 

眲名が怜蚌に合栌した堎合は、1が返されたす。それ以倖の堎合は0です。電子眲名を怜蚌するには、ドキュメントの眲名自䜓、眲名のタむプによっお決定されるドキュメントハッシュ、および眲名が䜜成された公開キヌずすべおのパラメヌタヌ倀、タむプ、パラメヌタヌが必芁です。 。 publickeyinfo asn1構造の圢匏のすべおのキヌ情報は、キヌ芁玠のリストに含める必芁がありたす。
lpkarpkcs11_handle= pkcsmod0
lpkarpkcs11_slotid= 0
lpkarpubkeyinfo= 301f06082a85030701010101301306072a85030202240
006082a8503070101020203430004407d9306687af5a8e63af4b09443ed2e03794be
10eba6627bf5fb3da1bb474a3507d2ce2cd24b63c727a02521897d1dd6edbdc7084d
8886a39289c3f81bdf2e179
ASN1公開鍵構造は、眲名者蚌明曞から取埗されたす。

 proc ::pki::x509::parse_cert_pubkeyinfo {cert_hex} { array set ret [list] set wholething [binary format H* $cert_hex] ::asn::asnGetSequence wholething cert ::asn::asnPeekByte cert peek_tag if {$peek_tag != 0x02} { # Version number is optional, if missing assumed to be value of 0 ::asn::asnGetContext cert - asn_version ::asn::asnGetInteger asn_version ret(version) } ::asn::asnGetBigInteger cert ret(serial_number) ::asn::asnGetSequence cert data_signature_algo_seq ::asn::asnGetObjectIdentifier data_signature_algo_seq ret(data_signature_algo) ::asn::asnGetSequence cert issuer ::asn::asnGetSequence cert validity ::asn::asnGetUTCTime validity ret(notBefore) ::asn::asnGetUTCTime validity ret(notAfter) ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo binary scan $pubkeyinfo H* ret(pubkeyinfo) return $ret(pubkeyinfo) } 

ファむルからの蚌明曞の電子眲名を怜蚌するためのスクリプトテキストがありたす
こっち
 #! /usr/bin/env tclsh package require pki lappend auto_path . package require pki::pkcs11 #     PKCS#11 #set pkcs11_module "/usr/local/lib/libcackey.so" #set pkcs11_module "/usr/local/lib64/librtpkcs11ecp_2.0.so" set pkcs11_module "/usr/local/lib64/libls11sw2016.so" puts "Connect the Token and press Enter" gets stdin yes set handle [pki::pkcs11::loadmodule $pkcs11_module] set slots [pki::pkcs11::listslots $handle] foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid #    break } } # PEM  DER proc ::cert_to_der {data} { if {[string first "-----BEGIN CERTIFICATE-----" $data] != -1} { set data [string map {"\r\n" "\n"} $data] } array set parsed_cert [::pki::_parse_pem $data "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] if {[string range $parsed_cert(data) 0 0 ] == "0" } { #   DER- "0" == 0x30 set asnblock $parsed_cert(data) } else { set asnblock "" } return $asnblock } proc usage {use error} { puts "Copyright(C) Orlov Vladimir (http://soft.lissi.ru) 2019" if {$use == 1} { puts $error puts "Usage:\nverify_cert_with_pkcs11 <file with certificate> \[<file with CA certificate>\]\n" } } set countcert [llength $argv] if { $countcert < 1 || $countcert > 2 } { usage 1 "Bad usage!" exit } set file [lindex $argv 0] if {![file exists $file]} { usage 1 "File $file not exist" exit } #  cert_user puts "Loading user certificate: $file" set fd [open $file] chan configure $fd -translation binary set cert_user [read $fd] close $fd if {$cert_user == "" } { usage 1 "Bad file with certificate user: $file" exit } set cert_user [cert_to_der $cert_user] if {$cert_user == ""} { puts "User certificate bad" exit } catch {array set cert_parse [::pki::x509::parse_cert $cert_user]} if {![info exists cert_parse]} { puts "User certificate bad" exit } #parray cert_parse if {$countcert == 1} { if {$cert_parse(issuer) != $cert_parse(subject)} { puts "Bad usage: not self signed certificate" } else { set cert_CA $cert_user } } else { set fileca [lindex $argv 1] if {![file exists $fileca]} { usage 1 "File $fileca not exist" exit } #  cert_CA puts "Loading CA certificate: $fileca" set fd [open $fileca] chan configure $fd -translation binary set cert_CA [read $fd] close $fd if {$cert_CA == "" } { usage 1 "Bad file with certificate CA=$fileca" exit } set cert_CA [cert_to_der $cert_CA] if {$cert_CA == ""} { puts "CA certificate bad" exit } } foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid } } #    #array set cert_parse_CA [::pki::x509::parse_cert $cert_CA] catch {array set cert_parse_CA [::pki::x509::parse_cert $cert_CA]} #array set cert_parse_CA [::pki::x509::parse_cert $cert_CA_256] #array set cert_parse_CA [::pki::x509::parse_cert $CA_12_512] if {![info exists cert_parse_CA]} { puts "CA certificate bad" exit } ############################### set aa [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] set tbs_cert [binary format H* $cert_parse(cert)] #puts "SIGN_ALGO1=$cert_parse(signature_algo)" catch {set signature_algo_number [::pki::_oid_name_to_number $cert_parse(signature_algo)]} if {![info exists signature_algo_number]} { set signature_algo_number $cert_parse(signature_algo) } #puts "SIGN_ALGO=$signature_algo_number" switch -- $signature_algo_number { "1.2.643.2.2.3" - "1 2 643 2 2 3" { # "GOST R 34.10-2001 with GOST R 34.11-94" set digest_algo "gostr3411" } "1.2.643.7.1.1.3.2" - "1 2 643 7 1 1 3 2" { # "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" set digest_algo "stribog256" } "1.2.643.7.1.1.3.3" - "1 2 643 7 1 1 3 3" { # "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" set digest_algo "stribog512" } default { puts "  :$signature_algo_number" exit } } #   tbs-!!!! set digest_hex [pki::pkcs11::digest $digest_algo $tbs_cert $aa] puts "digest_hex=$digest_hex" puts [string length $digest_hex] # asn-   #    binary scan $cert_CA H* cert_CA_hex array set infopk [pki::pkcs11::pubkeyinfo $cert_CA_hex [list pkcs11_handle $handle pkcs11_slotid $token_slotid]] parray infopk set lpk [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] # pybkeyinfo     lappend lpk "pubkeyinfo" #lappend lpk $pubinfo lappend lpk $infopk(pubkeyinfo) array set lpkar $lpk parray lpkar puts "Enter PIN user for you token \"$token_slotlabel\":" #set password "01234567" gets stdin password if { [pki::pkcs11::login $handle $token_slotid $password] == 0 } { puts "Bad password" exit } if {[catch {set verify [pki::pkcs11::verify $digest_hex $cert_parse(signature) $lpk]} res] } { puts $res exit } if {$verify != 1} { puts "BAD SIGNATURE=$verify" } else { puts "SIGNATURE OK=$verify" } puts "!" exit 


スクリプトをファむルに保存し、実行しおみおください。

 $./verify_cert_with_pkcs11.tcl Copyright(C) Orlov Vladimir (http://museum.lissi-crypto.ru/) Usage: verify_cert_with_pkcs11 <file with certificate> <file with CA certificate> $ 

トヌクン䞊の蚌明曞に぀いおはどうでしょうか たず、PKCS11暗号化マシンを䜿甚する問題を解決したした。 それらを䜿甚したした。 たた、トヌクン付きの蚌明曞を攟送するために、pki :: pkcs11 :: listcertsderパッケヌゞの機胜がありたす。これにより、目的の蚌明曞を遞択しお怜蚌するこずができたす。 これは宿題ず考えるこずができたす。

TclPKCS11v.1.0.1パッケヌゞの新しいバヌゞョンの登堎により、トヌクンの蚌明曞をむンポヌトする機胜、トヌクンから蚌明曞ず関連キヌを削陀する機胜、蚌明曞ずキヌのラベルを倉曎する機胜などを远加するこずにより 、蚌明曞衚瀺ナヌティリティを改良するこずが可胜になりたした



远加された最も重芁な機胜は、蚌明曞のデゞタル眲名怜蚌です。



気配りのある読者は、キヌペアの生成に぀いおは䜕も蚀われおいないこずを正しく指摘したした。 この機胜は、TclPKCS11パッケヌゞにも远加されたす。

 array set genkey [pki::pkcs11::keypair < > <> <  >] 

もちろん、TclPKCS11パッケヌゞの機胜がどのように䜿甚されるかは、ナヌティリティの゜ヌスコヌドに蚘茉されおいたす。

キヌペアを生成する機胜に぀いおは、次の蚘事で詳しく説明したす。PKCS11トヌクンでキヌペアを生成するこずにより、資栌蚌明曞のリク゚ストを䜜成するナヌティリティ、認蚌センタヌ CA で蚌明曞を取埗しおトヌクンにむンポヌトするメカニズムに぀いお説明したす



同じ蚘事では、文曞に眲名する機胜が考慮されたす。 これは、このシリヌズの最埌の蚘事になりたす。 次に、珟圚流行しおいるRubyスクリプト蚀語でロシアの暗号化をサポヌトする䞀連の蚘事が蚈画されおいたす。 じゃあね

Source: https://habr.com/ru/post/J449462/


All Articles