Skip to content

Commit

Permalink
feat: add rsa support for fingreprint
Browse files Browse the repository at this point in the history
  • Loading branch information
skynet2 committed Feb 15, 2024
1 parent 8dd4e25 commit 1c63140
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
56 changes: 56 additions & 0 deletions doc/util/fingerprint/fingerprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/binary"
"errors"
"fmt"
Expand All @@ -36,6 +38,9 @@ const (
// P521PubKeyMultiCodec for NIST P-521 public key in multicodec table.
P521PubKeyMultiCodec = 0x1202

// RSAPubKeyMultiCodec for RSA public key in multicodec table.
RSAPubKeyMultiCodec = 0x1205

// Default BLS 12-381 public key length in G2 field.
bls12381G2PublicKeyLen = 96

Expand Down Expand Up @@ -104,11 +109,62 @@ func CreateDIDKeyByJwk(jsonWebKey *jwk.JWK) (string, string, error) {
default:
return "", "", fmt.Errorf("unexpected OKP key type %T", key)
}
case "RSA":
key, ok := jsonWebKey.Key.(*rsa.PublicKey)
if !ok {
return "", "", fmt.Errorf("unexpected RSA key type %T", jsonWebKey.Key)
}

didKey, keyID := CreateDIDKeyByCode(RSAPubKeyMultiCodec, x509.MarshalPKCS1PublicKey(key))
return didKey, keyID, nil

Check failure on line 119 in doc/util/fingerprint/fingerprint.go

View workflow job for this annotation

GitHub Actions / Checks

return statements should not be cuddled if block has more than two lines (wsl)

default:
return "", "", fmt.Errorf("unsupported kty %s", jsonWebKey.Kty)
}
}

func encodeRSAPublicKey(modulus []byte, leadingZero bool, bits int) []byte {

Check failure on line 126 in doc/util/fingerprint/fingerprint.go

View workflow job for this annotation

GitHub Actions / Checks

`encodeRSAPublicKey` is unused (deadcode)
var header []byte
if leadingZero {

Check failure on line 128 in doc/util/fingerprint/fingerprint.go

View workflow job for this annotation

GitHub Actions / Checks

if statements should only be cuddled with assignments used in the if statement itself (wsl)
// If leading zero is required to ensure the modulus is positive in ASN.1/DER encoding,
// we add a zero byte at the beginning of the modulus.
modulus = append([]byte{0}, modulus...)
}

exponent := []byte{2, 3, 1, 0, 1} // Public exponent 65537 in DER encoding

// Construct the modulus part of the sequence
modulusLen := len(modulus)
modulusHeader := []byte{2} // INTEGER type
if modulusLen > 127 {

Check failure on line 139 in doc/util/fingerprint/fingerprint.go

View workflow job for this annotation

GitHub Actions / Checks

only one cuddle assignment allowed before if statement (wsl)
modulusHeader = append(modulusHeader, byte(0x82), byte(modulusLen>>8), byte(modulusLen&0xFF))
} else {
modulusHeader = append(modulusHeader, byte(modulusLen))
}
modulusSeq := append(modulusHeader, modulus...)

Check failure on line 144 in doc/util/fingerprint/fingerprint.go

View workflow job for this annotation

GitHub Actions / Checks

append only allowed to cuddle with appended value (wsl)

// Construct the full sequence with modulus and exponent
body := append(modulusSeq, exponent...)
seqLen := len(body)
if bits == 2048 {

Check failure on line 149 in doc/util/fingerprint/fingerprint.go

View workflow job for this annotation

GitHub Actions / Checks

`if bits == 2048` has complex nested blocks (complexity: 5) (nestif)
header = []byte{48} // SEQUENCE type
if seqLen > 127 {
header = append(header, byte(0x82), byte(seqLen>>8), byte(seqLen&0xFF))
} else {
header = append(header, byte(seqLen))
}
} else if bits == 4096 {
header = []byte{48} // SEQUENCE type
if seqLen > 127 {
header = append(header, byte(0x82), byte(seqLen>>8), byte(seqLen&0xFF))
} else {
header = append(header, byte(seqLen))
}
}

return append(header, body...)
}

func ecCodeAndCurve(ecCurve string) (uint64, elliptic.Curve, error) {
var (
curve elliptic.Curve
Expand Down
51 changes: 51 additions & 0 deletions doc/util/fingerprint/fingerprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"encoding/base64"
"fmt"
"math/big"
"strings"
"testing"

"github.com/btcsuite/btcutil/base58"
"github.com/go-jose/go-jose/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/trustbloc/kms-go/doc/jose/jwk"
Expand Down Expand Up @@ -303,6 +307,53 @@ func TestCreateDIDKeyByJwk(t *testing.T) {
})
}

func TestRSAFingerprint(t *testing.T) {
testKeys := []struct {
bitCount int
expectedPrefix string
}{
{
bitCount: 2048,
expectedPrefix: "did:key:z4MX",
},
{
bitCount: 4096,
expectedPrefix: "did:key:zgg",
},
}

for _, testKey := range testKeys {
t.Run(fmt.Sprint("RSA-", testKey.bitCount), func(t *testing.T) {
key, err := rsa.GenerateKey(rand.Reader, testKey.bitCount)
require.NoError(t, err)

jwkKey, err := jwksupport.JWKFromKey(&key.PublicKey)
require.NoError(t, err)

didKey, keyID, err := CreateDIDKeyByJwk(jwkKey)
require.NoError(t, err)

assert.NotEmpty(t, didKey)
assert.NotEmpty(t, keyID)
assert.True(t, strings.HasPrefix(didKey, testKey.expectedPrefix))
})
}
}

func TestRSAInvalidKey(t *testing.T) {
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)

jwkKey, err := jwksupport.JWKFromKey(&key.PublicKey)
require.NoError(t, err)

jwkKey.Key = "invalid key type"
didKey, keyID, err := CreateDIDKeyByJwk(jwkKey)
require.Empty(t, didKey)
require.Empty(t, keyID)
require.ErrorContains(t, err, "unexpected RSA key type string")
}

func TestDIDKeyEd25519(t *testing.T) {
const (
k1 = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
Expand Down

0 comments on commit 1c63140

Please sign in to comment.