ホームページ >バックエンド開発 >Golang >Go が生成した ECDSA 署名を JS を使用して検証できない

Go が生成した ECDSA 署名を JS を使用して検証できない

王林
王林転載
2024-02-10 20:03:07876ブラウズ

无法使用 JS 验证 Go 生成的 ECDSA 签名

php エディタ Xiaoxin は、Go 言語を使用して ECDSA 署名を生成するときに問題が発生しました。つまり、JS を検証に使用できませんでした。この問題の解決策は、Go コードにいくつかの追加フィールドを追加して、署名の正確性を保証することです。 Go コードにいくつかの変更を加えることで、この問題を解決し、JS が Go によって生成された ECDSA 署名を正しく検証できるようにすることができます。この記事では具体的な解決策と手順を詳しく紹介します。

質問内容

タイトルにあるように、小さな問題に遭遇しました(私は小さな問題が私を妨げていると仮定していますが、それが何かはわかりません)。

まず、私がやっていることの概要を説明し、それから私が持っているすべてを提供します。

プロジェクト概要

モバイル アプリで SHA-256 を使用してファイルをハッシュし、ECDSA P-256 キーを使用してバックエンドでハッシュに署名しています。そして、これが延々と続きます。ユーザーが望む場合は、ファイルを再度ハッシュし、ハッシュを検索してハッシュ、メタデータ、および署名を取得することで、ファイルの整合性を検証できます。

データが第三者ではなく私のアプリケーションに送信されたことを検証するために (ハッシュはブロックチェーンに残りますが、この問題では重要ではありません)、アプリケーションは公開キーを使用して署名を検証しようとします。 。この作品は良いです。

さて、このオプションを自分の Web サイトにも追加したいのですが、問題があります。 jsrsasign または webcrypto API を使用すると、署名が無効になります。

###データ###

署名の例:
    3045022100f28c29042a6d766810e21f2c0a1839f93140989299cae1d37b49a454373659c802203d0967be0696686414fe2efed3a71bc1639d066 ee1 27cfb7c0ad369521459d00
  • 公開鍵:
  • リーリー
ハッシュ値:
    bb5dfcb5206282627254ab23397cda842b082696466f2563503f79a5dccf942
  • ###脚本### JSコード リーリー アプリ認証コード(Flutter Dart) リーリー 鍵生成スクリプト (Go) リーリー
  • 署名ラッパー スクリプトへのリンク: link

私の試み

2 つの新しいキー ペア (およびライブラリ) を使用してサンプル データに署名し、キーの内容が間違っているかどうかをテストしましたが、そうではありません

私はあなたのライブラリと私の秘密鍵を使用して署名されたデータをテストし、私の公開鍵でそれを検証して、私の秘密鍵が破損しているかどうかを確認しましたが、そうではないことを確認しました
  • ネットワーク暗号化 API のすべての操作を試しましたが成功しませんでした
  • ECDSA
  • 公開キーをロードして、
  • new KJUR.crypto.ECDSA({"curve":"secp256r1"}).verifyHex(hash,signature,pubKeyHex)
  • を使用してみました。上記のデータでは機能しません(ブラウザコンソールでのみテストされています)
  • Firefox と Safari を使用して違いがあるかどうかを確認しましたが、何も変わりませんでした sig.updateString(hashData)
  • を介してハッシュ値を文字列として渡そうとしましたが、成功しませんでした
  • 他にも小さな変更がいくつかあります
  • Web サイトとアプリ Web サイトのハッシュ、R&S 署名を比較すると、すべてが予想どおりです。
  • フロントエンドからバックエンドまでプロセス全体を追跡しましたが、データは変更されていませんでした
  • 私の最後の試みは 4 回目でした。なぜなら、少なくとも私の理解では、通常の方法 (上記のスクリプトで行った) を使用すると、データはハッシュされるからです。これに関して言えば、それは生産性の逆です。すでにハッシュ値を取得しているため、2 回ハッシュ化すると、当然一致しません。しかし、理解できない理由により、戻り値として false が返されます。
  • 最後にもう一度考えてみましょう。
  • P-256
署名を使用している場合、問題は go ecdsa ライブラリがメッセージを 32 バイトに切り捨てることではないでしょうか?おそらくJSではそうではないでしょうか?

回避策

JavaScript コードでの検証は、次の 2 つの理由により Dart コードと互換性がありません。 <ul> <li>首先,JavaScript代码使用<a href="https://www.php.cn/link/971436431aef6875a9b7997990809a5f" rel="nofollow noreferrer"><code>KJUR.crypto.Signature (),它隐式对数据进行哈希处理。由于数据已经被散列,这会导致双重散列。在 Dart 方面,不会发生隐式哈希(因为 ECDSASigner())。
为了避免 JavaScript 端的隐式哈希并与 Dart 代码兼容,KJUR.crypto.ECDSA() 可以用来代替 KJUR.crypto.Signature()

  • 其次,JavaScript 代码中的 updateHex() 对十六进制编码的哈希值执行十六进制解码,而在 Dart 代码中,十六进制编码的哈希值是 UTF-8 编码的。
    为了与 Dart 代码兼容,十六进制编码的哈希值在 JavaScript 代码中也必须采用 UTF-8 编码。
  • 以下 JavaScript 代码解决了这两个问题:

    (async () => {
    
    var spki = `-----BEGIN PUBLIC KEY-----
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEq6iOuQeIhlhywCjo5yoABGODOJRZ
    c6/L8XzUYEsocCbc/JHiByGjuB3G9cSU2vUi1HUy5LsCtX2wlHSEObGVBw==
    -----END PUBLIC KEY-----`; 
    var pubkey = KEYUTIL.getKey(spki).getPublicKeyXYHex()
    var pubkeyHex = '04' + pubkey.x + pubkey.y
    
    var msgHashHex = ArrayBuffertohex(new TextEncoder().encode("bb5dbfcb5206282627254ab23397cda842b082696466f2563503f79a5dccf942").buffer)
    // var msgHashHex = ArrayBuffertohex(new TextEncoder().encode("bb5dbfcb5206282627254ab23397cda8").buffer); // works also since only the first 32 bytes are considered for P-256
    
    var sigHex = "3045022100f28c29042a6d766810e21f2c0a1839f93140989299cae1d37b49a454373659c802203d0967be0696686414fe2efed3a71bc1639d066ee127cfb7c0ad369521459d00"
    
    var ec = new KJUR.crypto.ECDSA({'curve': 'secp256r1'})
    var verified = ec.verifyHex(msgHashHex, sigHex, pubkeyHex)
    console.log("Verification:", verified)
     
    })();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/10.4.0/jsrsasign-all-min.js"></script>

    以上がGo が生成した ECDSA 署名を JS を使用して検証できないの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はstackoverflow.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。