javascript/golang RSA加密/验证

Iva*_*nov 3 javascript cryptography rsa go digital-signature

我在客户端上有以下javascript

var NodeRSA = require('node-rsa');

var ClientSide = new NodeRSA({ b: 512 });
var privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAj1IEeouqDYiMX0rMiPAI64UntzNxE01+tB+k+aKesHzVXE5A
GnyWHIFdrByfjR93CMh3y56xsL78VP1/Xp8iVmAnbiFN5kpmawJ1owhDvNIl8A+Q
UiDzMg0z/yepzjp61Dg4CUFzGrmTfYO1aMWyWhR0ZKfy+HvVaGjpod2ioScU7Fkz
eO+fDR85quLFta7OXDwqD4NCPYeZTS5fgK1Nn72nrItoj5e36fzWvZntfvi4NHt7
nqOj4VH5e5YJHvmLWHh5Swh+OVyIAwhxYSK5PSupicGG8ixVy75hkjzZ2vW5JdVW
MPYbVUMpqjtE+i1zQTYNJ36hM/zznZR/drU7UwIDAQABAoIBAHvs02qTMWuaUqZj
KxCNXWkpLfo/RNsH+zMM2b3xW34HswWps8wzRilHwxN7fIquVmMF1HAAvGyz98QV
nfjXaP1/DxkvOwiR9JU6/zUFhGzU2XEGRCh/zUnOGNPcG/vynRq7sdhu+3R0WpAB
Pu9lYp55aVtPzcwGZ7VsYfhQiLsGnJ5GkBS7z4P3aG29By6fGnTwR83iQHtR5SvQ
Rb/xJxZjTM00OZ2ssAtw24Hu8QXTuOAHdy2B5E1tsF+hVHs4iB0OiLzW7m4GBkb/
/og76ouB4G+j6IjG2E5TO0eAdslKn2w3dZRgqnVDF5CPtRdbAc83xOwSouuuqN26
FPsLkwECgYEA4Jyf3j9UzW0znnOcul4MDvfKuMCzD/5wnc24aYBbie4Joi/jqDbc
9J5jqyfgzdqwjxiwkEFJi7gBcclO1i1SoIfA6ooVoJeQlzdMpSytZVhzgE2aJO1E
ORP7kLimAHysjMJ27Fix1VRZltcZe0E9DErkw/hoPemAMvDvW2myyaECgYEAo1k7
iS4O9GSHUKvbEJWR5r+9Qvv4aObOaRFRDfq4/E9fZwujzKAvxwkGFXjxwpzxKJqN
paVEL2cWY+S46f4B501xgnNknuf6po8ZEaXD5vy281xoU4YX1KFySbV8eXGmkyiO
M2+vPGrsTGOIsKnQW8jmaxWTClbSdPoLWfwzqHMCgYAS/Kp2+xuMEgMfDd7d0j1q
tn+ohoGchIG4lT9Vi8gxLLIbx7iS67BZ7Vm3ijNys13hetDSIPK6oN9eYwoLCOHH
ODKSoQGbBbTvU3ljLRerTYLWAblaDcSKnqnRXgqKV/+uFnI/IHBH/E1mduBsjuM+
OsaD2mfVc/umUr+pFpJKgQKBgCeaTb3fhc6oxMnBMLZfnOT13Zvs3PgJ5UdB5IXg
IJNDZxzjjI3i1FKMFIaGMQ7+39T5S5g6bkKT2rDTViWc6Lc8ZmW7Nkz0byeMkAZg
SxOod26fG8gMPaDWl4/ZSVlkPX92GKvNyw152tpWU2CJezOVjI+vxlt+Wz3zFWd2
psuTAoGAbdlzYFK+7e2ru8fdbVk9SBLn9cnPdDCx+wgJV7dB0zzSh1oqIrE766Mx
c9wBIKWNqNEsFsFI4ejuMRdC4Hyc6ecCNea3nj3BHCS70V0p1MtFII6SpADDqBTW
3ZnLfcN2MiFDBXVqNkCsMcqd8KVdzEqEy1JDplmW84OpfQu88ms=
-----END RSA PRIVATE KEY-----`
var publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj1IEeouqDYiMX0rMiPAI
64UntzNxE01+tB+k+aKesHzVXE5AGnyWHIFdrByfjR93CMh3y56xsL78VP1/Xp8i
VmAnbiFN5kpmawJ1owhDvNIl8A+QUiDzMg0z/yepzjp61Dg4CUFzGrmTfYO1aMWy
WhR0ZKfy+HvVaGjpod2ioScU7FkzeO+fDR85quLFta7OXDwqD4NCPYeZTS5fgK1N
n72nrItoj5e36fzWvZntfvi4NHt7nqOj4VH5e5YJHvmLWHh5Swh+OVyIAwhxYSK5
PSupicGG8ixVy75hkjzZ2vW5JdVWMPYbVUMpqjtE+i1zQTYNJ36hM/zznZR/drU7
UwIDAQAB
-----END PUBLIC KEY-----`

ClientSide.importKey(privateKey, 'pkcs1');
let result = ClientSide.sign('test_message', 'base64')

console.log(result)

var serverSide = new NodeRSA({ b: 512 });
serverSide.importKey(publicKey, 'pkcs8-public');
console.log(serverSide.verify('test_message', new Buffer(result, 'base64')))
Run Code Online (Sandbox Code Playgroud)

它的输出是

baU/46UJYUp6Xt6sYs306t1vQdUOBRg10YuJPKspwLYj3aJHMgeQXMSfvBKvS+PJ3CMSVMVVjvoweNRu7A6ZzCSyVub9+qv0u5/2vSdUqiLDSHP5Gj9CRxsWPTLnapS27CJh3ywhqfgkuOSt6RZYTXqqoraHMP2jmGjfdLQmJbPiWamOc20u7xeTHK8oRmpXV0Pi5w4+7E6CkyfF9EfpLmmGGYiKqOWriWhYFbqkp+OV7FY4WRN1KwtmcZcnlWZ/4wAzg9uDL+8ZGyWKq62JY6Ee8LO5u6FCG7lU3KqBdq4eFKYI3CM9wdrxoZ7kNUlq0tQGZQ++MihdZQOfwj1vSA==

true
Run Code Online (Sandbox Code Playgroud)

因此,使用该代码段,我能够签名并验证消息.但是,我无法使用以下Go片段验证已签名的邮件.

package main

import (
  "crypto"
  "crypto/rsa"
  "crypto/x509"
  "encoding/base64"
  "encoding/pem"
  "errors"
  "fmt"
  "os"
)

func main() {

  toSign := "test_message"

  signed, err := base64.StdEncoding.DecodeString("baU/46UJYUp6Xt6sYs306t1vQdUOBRg10YuJPKspwLYj3aJHMgeQXMSfvBKvS+PJ3CMSVMVVjvoweNRu7A6ZzCSyVub9+qv0u5/2vSdUqiLDSHP5Gj9CRxsWPTLnapS27CJh3ywhqfgkuOSt6RZYTXqqoraHMP2jmGjfdLQmJbPiWamOc20u7xeTHK8oRmpXV0Pi5w4+7E6CkyfF9EfpLmmGGYiKqOWriWhYFbqkp+OV7FY4WRN1KwtmcZcnlWZ/4wAzg9uDL+8ZGyWKq62JY6Ee8LO5u6FCG7lU3KqBdq4eFKYI3CM9wdrxoZ7kNUlq0tQGZQ++MihdZQOfwj1vSA==")
  if err != nil {
    println("unable do decode")
    os.Exit(1)
  }

  parser, err := loadPublicKey()
  if err != nil {
    println("unable to load public key")
    os.Exit(1)
  }

  err = parser.Unsign([]byte(toSign), signed)
  if err != nil {
    println("unable to verify")
    os.Exit(1)
  }

}

func loadPublicKey() (Unsigner, error) {

  return parsePublicKey([]byte(`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj1IEeouqDYiMX0rMiPAI
64UntzNxE01+tB+k+aKesHzVXE5AGnyWHIFdrByfjR93CMh3y56xsL78VP1/Xp8i
VmAnbiFN5kpmawJ1owhDvNIl8A+QUiDzMg0z/yepzjp61Dg4CUFzGrmTfYO1aMWy
WhR0ZKfy+HvVaGjpod2ioScU7FkzeO+fDR85quLFta7OXDwqD4NCPYeZTS5fgK1N
n72nrItoj5e36fzWvZntfvi4NHt7nqOj4VH5e5YJHvmLWHh5Swh+OVyIAwhxYSK5
PSupicGG8ixVy75hkjzZ2vW5JdVWMPYbVUMpqjtE+i1zQTYNJ36hM/zznZR/drU7
UwIDAQAB
-----END PUBLIC KEY-----`))
}

func parsePublicKey(pemBytes []byte) (Unsigner, error) {
  block, _ := pem.Decode(pemBytes)
  if block == nil {
    return nil, errors.New("ssh: no key found")
  }

  var rawkey interface{}
  switch block.Type {
  case "PUBLIC KEY":
    rsa, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
      return nil, err
    }
    rawkey = rsa
  default:
    return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
  }

  return newUnsignerFromKey(rawkey)
}

type Unsigner interface {
  // Sign returns raw signature for the given data. This method
  // will apply the hash specified for the keytype to the data.
  Unsign(data []byte, sig []byte) error
}

func newUnsignerFromKey(k interface{}) (Unsigner, error) {
  var sshKey Unsigner
  switch t := k.(type) {
  case *rsa.PublicKey:
    sshKey = &rsaPublicKey{t}
  default:
    return nil, fmt.Errorf("ssh: unsupported key type %T", k)
  }
  return sshKey, nil
}

type rsaPublicKey struct {
  *rsa.PublicKey
}

func (r *rsaPublicKey) Unsign(message []byte, sig []byte) error {
  var opts rsa.PSSOptions
  opts.SaltLength = rsa.PSSSaltLengthAuto
  PSSmessage := message
  newhash := crypto.SHA256
  pssh := newhash.New()
  pssh.Write(PSSmessage)
  hashed := pssh.Sum(nil)
  return rsa.VerifyPSS(r.PublicKey, newhash, hashed, sig, &opts)
}
Run Code Online (Sandbox Code Playgroud)

该片段被发现,并从其他答案稍作修改,但我无法使其工作.

Maa*_*wes 6

Node-RSA页面:

signingScheme - 用于签名和验证的方案.可以是'pkcs1'或者是'pss''scheme-hash'格式的字符串(例如'pss-sha1').默认'pkcs1-sha256',或者,如果选择了pss : 'pss-sha1'.

因此,NodeJS实现使用带有SHA-256的PKCS#1 v1.5填充,而Go使用带有SHA-256的PSS填充.

您基本上需要确保您的签名算法及其参数匹配.请注意,如果您使用PSS并且代码仍然失败,您可能还需要确保用于MGF1的哈希函数(PSS中的掩码生成函数)匹配.