-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
543 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package eckcdsa | ||
|
||
import ( | ||
"errors" | ||
"hash" | ||
"io" | ||
"math/big" | ||
|
||
"golang.org/x/crypto/cryptobyte" | ||
Check failure on line 9 in eckcdsa/eckcdsa_asn1.go GitHub Actions / macos_arm64 (1.17)
Check failure on line 9 in eckcdsa/eckcdsa_asn1.go GitHub Actions / macos_arm64 (1.18)
Check failure on line 9 in eckcdsa/eckcdsa_asn1.go GitHub Actions / ubuntu_amd64 (1.20)
|
||
"golang.org/x/crypto/cryptobyte/asn1" | ||
Check failure on line 10 in eckcdsa/eckcdsa_asn1.go GitHub Actions / macos_arm64 (1.17)
Check failure on line 10 in eckcdsa/eckcdsa_asn1.go GitHub Actions / macos_arm64 (1.18)
Check failure on line 10 in eckcdsa/eckcdsa_asn1.go GitHub Actions / ubuntu_amd64 (1.20)
|
||
) | ||
|
||
// Sign data using K generated randomly like in crypto/ecdsa packages. | ||
// SianASN1 returns the ASN.1 encoded signature. | ||
func SignASN1(randReader io.Reader, priv *PrivateKey, h hash.Hash, M []byte) (sig []byte, err error) { | ||
r, s, err := Sign(randReader, priv, h, M) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return encodeSignature(r.Bytes(), s.Bytes()) | ||
} | ||
|
||
// VerifyASN1 verifies the ASN.1 encoded signature, sig, M, of hash using the | ||
// public key, pub. Its return value records whether the signature is valid. | ||
func VerifyASN1(pub *PublicKey, h hash.Hash, M, sig []byte) bool { | ||
r, s, err := parseSignature(sig) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
return Verify( | ||
pub, | ||
h, | ||
M, | ||
new(big.Int).SetBytes(r), | ||
new(big.Int).SetBytes(s), | ||
) | ||
} | ||
|
||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/ecdsa/ecdsa.go#L338-L345 | ||
func encodeSignature(r, s []byte) ([]byte, error) { | ||
var b cryptobyte.Builder | ||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { | ||
addASN1IntBytes(b, r) | ||
addASN1IntBytes(b, s) | ||
}) | ||
return b.Bytes() | ||
} | ||
|
||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/ecdsa/ecdsa.go#L349-L363 | ||
func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) { | ||
for len(bytes) > 0 && bytes[0] == 0 { | ||
bytes = bytes[1:] | ||
} | ||
if len(bytes) == 0 { | ||
b.SetError(errors.New("invalid integer")) | ||
return | ||
} | ||
b.AddASN1(asn1.INTEGER, func(c *cryptobyte.Builder) { | ||
if bytes[0]&0x80 != 0 { | ||
c.AddUint8(0) | ||
} | ||
c.AddBytes(bytes) | ||
}) | ||
} | ||
|
||
// https://github.com/golang/go/blob/master/src/crypto/ecdsa/ecdsa.go#L549-L560 | ||
func parseSignature(sig []byte) (r, s []byte, err error) { | ||
var inner cryptobyte.String | ||
input := cryptobyte.String(sig) | ||
if !input.ReadASN1(&inner, asn1.SEQUENCE) || | ||
!input.Empty() || | ||
!inner.ReadASN1Integer(&r) || | ||
!inner.ReadASN1Integer(&s) || | ||
!inner.Empty() { | ||
return nil, nil, errors.New("invalid ASN.1") | ||
} | ||
return r, s, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package eckcdsa | ||
|
||
/** | ||
FROM GO 1.21.6 SOURCE CODE | ||
*/ | ||
|
||
import ( | ||
"crypto/x509/pkix" | ||
"encoding/asn1" | ||
"errors" | ||
) | ||
|
||
func ParseECPrivateKey(der []byte) (*PrivateKey, error) { | ||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/sec1.go#L37-L39 | ||
return parseECPrivateKey(nil, der) | ||
} | ||
func (key *PrivateKey) MarshalECPrivateKey() ([]byte, error) { | ||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/sec1.go#L46-L53 | ||
oid, ok := oidFromNamedCurve(key.Curve) | ||
if !ok { | ||
return nil, errors.New("eckcdsa: unknown elliptic curve") | ||
} | ||
|
||
return marshalECPrivateKeyWithOID(key, oid) | ||
} | ||
|
||
func ParsePKCS8PrivateKey(der []byte) (key *PrivateKey, err error) { | ||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/pkcs8.go#L35-L45 | ||
var privKey pkcs8 | ||
if _, err := asn1.Unmarshal(der, &privKey); err != nil { | ||
if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil { | ||
return nil, errors.New("eckcdsa: failed to parse private key (use ParseECPrivateKey instead for this key format)") | ||
} | ||
return nil, err | ||
} | ||
|
||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/pkcs8.go#L54-L64 | ||
bytes := privKey.Algo.Parameters.FullBytes | ||
namedCurveOID := new(asn1.ObjectIdentifier) | ||
if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil { | ||
namedCurveOID = nil | ||
} | ||
key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey) | ||
if err != nil { | ||
return nil, errors.New("eckcdsa: failed to parse EC private key embedded in PKCS#8: " + err.Error()) | ||
} | ||
return key, nil | ||
} | ||
func (k *PrivateKey) MarshalPKCS8PrivateKey() ([]byte, error) { | ||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/pkcs8.go#L101-L102 | ||
var privKey pkcs8 | ||
|
||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/pkcs8.go#L112-L129 | ||
oid, ok := oidFromNamedCurve(k.Curve) | ||
if !ok { | ||
return nil, errors.New("eckcdsa: unknown curve while marshaling to PKCS#8") | ||
} | ||
oidBytes, err := asn1.Marshal(oid) | ||
if err != nil { | ||
return nil, errors.New("eckcdsa: failed to marshal curve OID: " + err.Error()) | ||
} | ||
privKey.Algo = pkix.AlgorithmIdentifier{ | ||
Algorithm: oidPublicKeyECDSA, | ||
Parameters: asn1.RawValue{ | ||
FullBytes: oidBytes, | ||
}, | ||
} | ||
if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil { | ||
return nil, errors.New("eckcdsa: failed to marshal EC private key while building PKCS#8: " + err.Error()) | ||
} | ||
|
||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/pkcs8.go#L174C2-L174C30 | ||
return asn1.Marshal(privKey) | ||
} | ||
|
||
func ParsePKIXPublicKey(derBytes []byte) (key *PublicKey, err error) { | ||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/x509.go#L71-L82 | ||
var pki publicKeyInfo | ||
if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { | ||
return nil, err | ||
} else if len(rest) != 0 { | ||
return nil, errors.New("eckcdsa: trailing data after ASN.1 of public-key") | ||
} | ||
return parsePublicKey(&pki) | ||
} | ||
func (pub *PublicKey) MarshalPKIXPublicKey() ([]byte, error) { | ||
// https://github.com/golang/go/blob/go1.21.6/src/crypto/x509/x509.go#L150-L169 | ||
var publicKeyBytes []byte | ||
var publicKeyAlgorithm pkix.AlgorithmIdentifier | ||
var err error | ||
|
||
if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil { | ||
return nil, err | ||
} | ||
|
||
pkix := pkixPublicKey{ | ||
Algo: publicKeyAlgorithm, | ||
BitString: asn1.BitString{ | ||
Bytes: publicKeyBytes, | ||
BitLength: 8 * len(publicKeyBytes), | ||
}, | ||
} | ||
|
||
ret, _ := asn1.Marshal(pkix) | ||
return ret, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package eckcdsa | ||
|
||
import ( | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"testing" | ||
) | ||
|
||
var ( | ||
curveList = []elliptic.Curve{ | ||
elliptic.P224(), | ||
elliptic.P256(), | ||
elliptic.P384(), | ||
elliptic.P521(), | ||
} | ||
|
||
testCases []struct { | ||
PrivateKey *PrivateKey | ||
Marshaled []byte | ||
} | ||
) | ||
|
||
func TestPKIXPublicKey(t *testing.T) { | ||
for _, curve := range curveList { | ||
p1p, _ := GenerateKey(curve, rand.Reader) | ||
p1 := p1p.PublicKey | ||
|
||
der, err := p1.MarshalPKIXPublicKey() | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
p2, err := ParsePKIXPublicKey(der) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
if !p1.Equal(p2) { | ||
t.Error("not equals!") | ||
return | ||
} | ||
} | ||
} | ||
func TestMarshal(t *testing.T) { | ||
for _, curve := range curveList { | ||
p1, _ := GenerateKey(curve, rand.Reader) | ||
|
||
der, err := p1.MarshalECPrivateKey() | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
p2, err := ParseECPrivateKey(der) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
if !p1.Equal(p2) { | ||
t.Error("not equals!") | ||
return | ||
} | ||
} | ||
} | ||
func TestPKCS8PrivateKey(t *testing.T) { | ||
for _, curve := range curveList { | ||
p1, _ := GenerateKey(curve, rand.Reader) | ||
|
||
der, err := p1.MarshalPKCS8PrivateKey() | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
p2, err := ParsePKCS8PrivateKey(der) | ||
if err != nil { | ||
t.Error(err) | ||
return | ||
} | ||
|
||
if !p1.Equal(p2) { | ||
t.Error("not equals!") | ||
return | ||
} | ||
} | ||
} | ||
|
||
func TestParseECPrivateKey(t *testing.T) { | ||
} | ||
func TestParsePKCS8PrivateKey(t *testing.T) { | ||
} | ||
func TestMarshalECPrivateKey(t *testing.T) { | ||
} | ||
func TestMarshalPKCS8PrivateKey(t *testing.T) { | ||
} | ||
func TestMarshalPKIXPublicKey(t *testing.T) { | ||
|
||
} |
Oops, something went wrong.