文字列、署名、公開鍵があり、文字列の署名を確認したいと思います。キーは次のようになります。
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----
Pycryptoのドキュメントをしばらく読んでいますが、この種のキーを使用してRSAobjを作成する方法がわかりません。あなたがPHPを知っているなら、私は次のことをしようとしています:
openssl_verify($data, $signature, $public_key, OPENSSL_ALGO_SHA1);
また、用語がわからない場合はお知らせください。
マーカー間のデータは、PSN.1 DERのbase64エンコーディングです。PKCS#1RSAPublicKeyを含むPKCS#8PublicKeyInfoのエンコーディングです。
これは多くの標準であり、暗号化ライブラリを使用してデコードするのが最適です(M2Crypto as joeforkerが提案 など)。以下をフォーマットに関する楽しい情報として扱ってください。
必要に応じて、次のようにデコードできます。
Base64-文字列をデコードします:
30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001
これは、次のDERエンコーディングです。
0 30 159: SEQUENCE {
3 30 13: SEQUENCE {
5 06 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
16 05 0: NULL
: }
18 03 141: BIT STRING 0 unused bits, encapsulates {
22 30 137: SEQUENCE {
25 02 129: INTEGER
: 00 DF 1B 82 2E 14 ED A1 FC B7 43 36 6A 27 C0 63
: 70 E6 CA D6 9D 41 16 CE 80 6B 3D 11 75 34 CF 0B
: AA 93 8C 0F 8E 45 00 FB 59 D4 D9 8F B4 71 A8 D0
: 10 12 D5 4B 32 24 41 97 C7 43 4F 27 C1 B0 D7 3F
: A1 B8 BA E5 5E 70 15 5F 90 78 79 CE 9C 25 F2 8A
: 9A 92 FF 97 DE 16 84 FD AF F0 5D CE 19 6A E7 68
: 45 F5 98 B3 28 C5 ED 76 E0 F7 1F 6A 6B 74 48 F0
: 86 91 E6 A5 56 F5 F0 D7 73 CB 20 D1 3F 62 9B 63
: 91
157 02 3: INTEGER 65537
: }
: }
: }
1024ビットのRSAキーの場合、"30819f300d06092a864886f70d010101050003818d00308189028181"
を定数ヘッダー、00バイト、128バイトのRSAモジュラスとして扱うことができます。その後、95%の時間で0203010001
が取得されます。これは、RSA公開指数が0x10001 = 65537であることを示します。
タプルでこれらの2つの値をn
およびe
として使用して、RSAobjを作成できます。
M2Crypto を使用します。 RSAおよびOpenSSLでサポートされているその他のアルゴリズムを確認する方法は次のとおりです。
pem = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----""" # your example key
from M2Crypto import BIO, RSA, EVP
bio = BIO.MemoryBuffer(pem)
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
# if you need a different digest than the default 'sha1':
pubkey.reset_context(md='sha1')
pubkey.verify_init()
pubkey.verify_update('test message')
assert pubkey.verify_final(signature) == 1
公開鍵には、モジュラス(非常に長い数値、1024ビット、2058ビット、4096ビット)と公開鍵指数(はるかに小さい数値、通常は2の1乗に等しい)の両方が含まれます。何かを行う前に、その公開鍵を2つのコンポーネントに分割する方法を見つける必要があります。
Pycryptoについてはよくわかりませんが、署名を確認するには、文字列のハッシュを取得します。次に、署名を復号化する必要があります。 べき乗剰余 ;を読んでください。署名を復号化する式はmessage^public exponent % modulus
。最後のステップは、作成したハッシュと取得した復号化された署名が同じであるかどうかを確認することです。
ezPyCrypto はこれを少し簡単にするかもしれないと思います。 keyクラスの高レベルのメソッドには、問題の解決に役立つと思われる次の2つのメソッドが含まれています。
Rasmus は、コメントでverifyString
がMD5を使用するようにハードコードされていることを指摘しています。この場合、ezPyCrytoはAndrewがコードに手を出さない限り助けられません。 joeforkerの答え :検討 M2Crypto 。
DERデコードの詳細。
DERエンコーディングは常にTLVトリプレットフォーマットに従います:(タグ、長さ、値)
タグは基本的に、値フィールドのバイトデータを解釈する方法を示します。 ANS.1には型システムがあります。 0x02は整数を意味し、0x30はシーケンス(1つ以上の他のタイプインスタンスの順序付けられたコレクション)を意味します。
長さの表示には特別なロジックがあります。
たとえば、256バイトの長さの数値をエンコードするとすると、次のようになります。
02 82 01 00 1F 2F 3F 4F … DE AD BE EF
今あなたの例を見てください
30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001
それはラスマス・フェイバーが彼の返事に書いたものとして解釈されます
M2Cryptoを使用すると、上記の回答は機能しません。これがテストされた例です。
import base64
import hashlib
import M2Crypto as m2
# detach the signature from the message if it's required in it (useful for url encoded data)
message_without_sign = message.split("&SIGN=")[0]
# decode base64 the signature
binary_signature = base64.b64decode(signature)
# create a pubkey object with the public key stored in a separate file
pubkey = m2.RSA.load_pub_key(os.path.join(os.path.dirname(__file__), 'pubkey.pem'))
# verify the key
assert pubkey.check_key(), 'Key Verification Failed'
# digest the message
sha1_hash = hashlib.sha1(message_without_sign).digest()
# and verify the signature
assert pubkey.verify(data=sha1_hash, signature=binary_signature), 'Certificate Verification Failed'
そしてそれはそれについてです
これはあなたが探している答えではないかもしれませんが、必要なのはキーをビットに変換することだけであれば、Base64でエンコードされているように見えます。標準のPythonライブラリにあるcodecs
モジュール(私は思う)を見てください。