471 lines
16 KiB
Go
471 lines
16 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/ecdh"
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Test data structures
|
|
type TestData struct {
|
|
Timestamp string
|
|
RandHex string
|
|
Combined string
|
|
}
|
|
|
|
// Helper function to generate P-256 key pair (used for both hardware and acceleration keys)
|
|
func generateP256KeyPair() (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) {
|
|
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return privKey, &privKey.PublicKey, nil
|
|
}
|
|
|
|
// Helper function to generate test data
|
|
func generateTestData() *TestData {
|
|
timestamp := fmt.Sprintf("%d", time.Now().UnixNano())
|
|
randBytes := make([]byte, 16)
|
|
rand.Read(randBytes)
|
|
randHex := hex.EncodeToString(randBytes)
|
|
|
|
return &TestData{
|
|
Timestamp: timestamp,
|
|
RandHex: randHex,
|
|
Combined: timestamp + "-" + randHex,
|
|
}
|
|
}
|
|
|
|
// Single comprehensive benchmark test for the complete cryptographic workflow
|
|
func BenchmarkCompleteWorkflow(b *testing.B) {
|
|
b.Logf("Starting comprehensive cryptographic workflow benchmark")
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
// Step 1: Prepare keys - create hw key pair (ecdsa-p256)
|
|
hwPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
b.Fatal("Failed to generate hardware key pair:", err)
|
|
}
|
|
hwPub := &hwPriv.PublicKey
|
|
|
|
// Step 1: Create accel key pair (P-256 for both signing and ECDH)
|
|
accelPriv, accelPub, err := generateP256KeyPair()
|
|
if err != nil {
|
|
b.Fatal("Failed to generate acceleration key pair:", err)
|
|
}
|
|
|
|
// Step 2: Sign accel pub by hw priv
|
|
accelPubBytes := elliptic.Marshal(elliptic.P256(), accelPub.X, accelPub.Y)
|
|
r, s, err := ecdsa.Sign(rand.Reader, hwPriv, accelPubBytes[:])
|
|
if err != nil {
|
|
b.Fatal("Failed to sign acceleration public key:", err)
|
|
}
|
|
|
|
// Step 3: Sign data (timestamp-randhex) by accel priv
|
|
testData := generateTestData()
|
|
dataHash := sha256.Sum256([]byte(testData.Combined))
|
|
dataR, dataS, err := ecdsa.Sign(rand.Reader, accelPriv, dataHash[:])
|
|
if err != nil {
|
|
b.Fatal("Failed to sign test data:", err)
|
|
}
|
|
|
|
// Step 4: Server verify accel pub by hw pub
|
|
if !ecdsa.Verify(hwPub, accelPubBytes[:], r, s) {
|
|
b.Fatal("Failed to verify acceleration public key signature")
|
|
}
|
|
|
|
// Step 5: Server verify data sig by accel pub
|
|
if !ecdsa.Verify(accelPub, dataHash[:], dataR, dataS) {
|
|
b.Fatal("Failed to verify data signature")
|
|
}
|
|
|
|
// Step 6: Create server ecdh-p256 key pair and do key exchange with accel pub
|
|
// Convert to ECDH format
|
|
accelPubECDHBytes := elliptic.Marshal(elliptic.P256(), accelPub.X, accelPub.Y)
|
|
curve := ecdh.P256()
|
|
clientECDHPub, err := curve.NewPublicKey(accelPubECDHBytes)
|
|
if err != nil {
|
|
b.Fatal("Failed to create client ECDH public key:", err)
|
|
}
|
|
|
|
// Generate server ECDH key pair
|
|
serverECDHPriv, err := curve.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
b.Fatal("Failed to generate server ECDH key pair:", err)
|
|
}
|
|
|
|
// Perform key exchange
|
|
sharedSecret, err := serverECDHPriv.ECDH(clientECDHPub)
|
|
if err != nil {
|
|
b.Fatal("Failed to perform ECDH key exchange:", err)
|
|
}
|
|
|
|
// Verify we got a valid shared secret
|
|
if len(sharedSecret) == 0 {
|
|
b.Fatal("Empty shared secret from ECDH")
|
|
}
|
|
|
|
// Log progress every 100 iterations for longer benchmarks
|
|
if (i+1)%100 == 0 {
|
|
b.Logf("Completed %d iterations successfully", i+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Single comprehensive test for the complete cryptographic workflow
|
|
func TestCompleteWorkflow(t *testing.T) {
|
|
t.Logf("Starting comprehensive cryptographic workflow test")
|
|
|
|
// Step 1: Prepare keys - create hw key pair (ecdsa-p256)
|
|
t.Log("Step 1: Generating hardware key pair (ECDSA P-256)")
|
|
hwPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatal("Failed to generate hardware key pair:", err)
|
|
}
|
|
hwPub := &hwPriv.PublicKey
|
|
t.Logf("Hardware P-256 public key: %s", base64.StdEncoding.EncodeToString(elliptic.Marshal(elliptic.P256(), hwPub.X, hwPub.Y)))
|
|
|
|
// Step 1: Create accel key pair (P-256 for both signing and ECDH)
|
|
t.Log("Step 1: Generating acceleration key pair (P-256)")
|
|
accelPriv, accelPub, err := generateP256KeyPair()
|
|
if err != nil {
|
|
t.Fatal("Failed to generate acceleration key pair:", err)
|
|
}
|
|
t.Logf("Acceleration P-256 public key: %s", base64.StdEncoding.EncodeToString(elliptic.Marshal(elliptic.P256(), accelPub.X, accelPub.Y)))
|
|
|
|
// Step 2: Sign accel pub by hw priv
|
|
t.Log("Step 2: Signing acceleration public key with hardware private key")
|
|
accelPubBytes := elliptic.Marshal(elliptic.P256(), accelPub.X, accelPub.Y)
|
|
accelPubHash := sha256.Sum256(accelPubBytes)
|
|
r, s, err := ecdsa.Sign(rand.Reader, hwPriv, accelPubHash[:])
|
|
if err != nil {
|
|
t.Fatal("Failed to sign acceleration public key:", err)
|
|
}
|
|
t.Logf("Acceleration public key signature: r=%s", r.String())
|
|
|
|
// Step 3: Sign data (timestamp-randhex) by accel priv
|
|
t.Log("Step 3: Generating test data and signing with acceleration private key")
|
|
testData := generateTestData()
|
|
t.Logf("Test data: %s", testData.Combined)
|
|
dataHash := sha256.Sum256([]byte(testData.Combined))
|
|
dataR, dataS, err := ecdsa.Sign(rand.Reader, accelPriv, dataHash[:])
|
|
if err != nil {
|
|
t.Fatal("Failed to sign test data:", err)
|
|
}
|
|
t.Logf("Data signature created successfully")
|
|
|
|
// Step 4: Server verify accel pub by hw pub
|
|
t.Log("Step 4: Server verifying acceleration public key signature")
|
|
if !ecdsa.Verify(hwPub, accelPubHash[:], r, s) {
|
|
t.Fatal("Failed to verify acceleration public key signature")
|
|
}
|
|
t.Log("✓ Acceleration public key signature verified successfully")
|
|
|
|
// Step 5: Server verify data sig by accel pub
|
|
t.Log("Step 5: Server verifying data signature")
|
|
if !ecdsa.Verify(accelPub, dataHash[:], dataR, dataS) {
|
|
t.Fatal("Failed to verify data signature")
|
|
}
|
|
t.Log("✓ Data signature verified successfully")
|
|
|
|
// Step 6: Create server ecdh-p256 key pair and do key exchange with accel pub
|
|
t.Log("Step 6: Performing ECDH key exchange")
|
|
|
|
// Convert to ECDH format
|
|
accelPubECDHBytes := elliptic.Marshal(elliptic.P256(), accelPub.X, accelPub.Y)
|
|
curve := ecdh.P256()
|
|
clientECDHPub, err := curve.NewPublicKey(accelPubECDHBytes)
|
|
if err != nil {
|
|
t.Fatal("Failed to create client ECDH public key:", err)
|
|
}
|
|
|
|
// Generate server ECDH key pair
|
|
serverECDHPriv, err := curve.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
t.Fatal("Failed to generate server ECDH key pair:", err)
|
|
}
|
|
|
|
serverECDHPub, _ := x509.MarshalPKIXPublicKey(serverECDHPriv.PublicKey())
|
|
t.Logf("Server ECDH public key: %s", base64.StdEncoding.EncodeToString(serverECDHPub))
|
|
|
|
// Perform key exchange
|
|
sharedSecret, err := serverECDHPriv.ECDH(clientECDHPub)
|
|
if err != nil {
|
|
t.Fatal("Failed to perform ECDH key exchange:", err)
|
|
}
|
|
|
|
// Verify we got a valid shared secret
|
|
if len(sharedSecret) == 0 {
|
|
t.Fatal("Empty shared secret from ECDH")
|
|
}
|
|
t.Logf("✓ ECDH key exchange successful! Shared secret length: %d bytes", len(sharedSecret))
|
|
t.Logf("Shared secret: %s", base64.StdEncoding.EncodeToString(sharedSecret))
|
|
|
|
t.Log("🎉 Complete cryptographic workflow test passed successfully!")
|
|
}
|
|
|
|
// Performance comparison test
|
|
func TestPerformanceComparison(t *testing.T) {
|
|
const iterations = 100
|
|
|
|
t.Run("P256Operations", func(t *testing.T) {
|
|
// Time key generation
|
|
start := time.Now()
|
|
for i := 0; i < iterations; i++ {
|
|
_, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
keyGenDuration := time.Since(start)
|
|
|
|
// Time signing operations
|
|
hwPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
testData := []byte("performance test data")
|
|
hash := sha256.Sum256(testData)
|
|
|
|
start = time.Now()
|
|
for i := 0; i < iterations; i++ {
|
|
_, _, err := ecdsa.Sign(rand.Reader, hwPriv, hash[:])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
signDuration := time.Since(start)
|
|
|
|
// Time verification operations
|
|
r, s, _ := ecdsa.Sign(rand.Reader, hwPriv, hash[:])
|
|
start = time.Now()
|
|
for i := 0; i < iterations; i++ {
|
|
if !ecdsa.Verify(&hwPriv.PublicKey, hash[:], r, s) {
|
|
t.Fatal("verification failed")
|
|
}
|
|
}
|
|
verifyDuration := time.Since(start)
|
|
|
|
// Time ECDH operations
|
|
curve := ecdh.P256()
|
|
start = time.Now()
|
|
for i := 0; i < iterations; i++ {
|
|
priv1, _ := curve.GenerateKey(rand.Reader)
|
|
priv2, _ := curve.GenerateKey(rand.Reader)
|
|
_, err := priv1.ECDH(priv2.PublicKey())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
ecdhDuration := time.Since(start)
|
|
|
|
// Report results
|
|
t.Logf("P-256 Performance Results (%d iterations):", iterations)
|
|
t.Logf("Key generation: %v (avg: %v)", keyGenDuration, keyGenDuration/iterations)
|
|
t.Logf("Signing: %v (avg: %v)", signDuration, signDuration/iterations)
|
|
t.Logf("Verification: %v (avg: %v)", verifyDuration, verifyDuration/iterations)
|
|
t.Logf("ECDH: %v (avg: %v)", ecdhDuration, ecdhDuration/iterations)
|
|
})
|
|
}
|
|
|
|
// Test ECDSA P-256 signature verification with provided test data
|
|
func TestECDSAP256SignatureVerification(t *testing.T) {
|
|
t.Log("Testing ECDSA P-256 signature verification with provided test data")
|
|
|
|
// Test data sets
|
|
testCases := []struct {
|
|
name string
|
|
publicKeyB64 string
|
|
plaintextB64 string
|
|
signatures []string
|
|
}{
|
|
{
|
|
name: "Windows",
|
|
publicKeyB64: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEs7QlaLpB0jw6DQvyLyDtOqzvrrjHvrKqAnys6qgGyqozpku3tS/gwvcKNBDifyr05UYHYAcLzyLNJ57XYkPPiw==",
|
|
plaintextB64: "1234567890==",
|
|
signatures: []string{
|
|
"YLvs+xya4PZU2/jz8saWk/tPlja4B9mkz6iDAHf1OfsMZDhtThpP5JMCtJociPp/sZGHq/4+LF5ndR4DYeCD6A==",
|
|
"Mvm0l6My9Cz8wXea8XFuRTNqYpDQuu+1qNzJyyoOI/WFwYsm/782HyHC4OOanZYtCtK2yUuFEUhvrHC8UA37rA==",
|
|
"1BYuwr05K8BC9YYScWwUSrQac71cmnj8so8Auukt2XiNm6o5R/ZauVdlzdCovLu9Y1EFYtfM4Ij0wSatXqMOcA==",
|
|
"YFfguSt6i6zUZwiRGKfJeFoDeDa6ZZ2Iknx0NUBNjyX054MJFr/IolsyDUefv+206y8VRk+3vPFcdJBre3K76Q==",
|
|
},
|
|
},
|
|
{
|
|
name: "macOS",
|
|
publicKeyB64: "BJQ+7eXZcgPnI5P73nGlsgn3RCY1yLEhdA3KJNnrUbniC0LaSlUtMpaBhzeQjgRYZYi4wPSVfLJZ9T8Ao5CRai8=",
|
|
plaintextB64: "1234567890==",
|
|
signatures: []string{
|
|
"MEUCIQDfWzCdfE50ZM/HsfO55PHIgqR5C+jg1WiwK1HVHLlSRQIgDnG2Xxhr4S+SWlHNWHgzaxeMVV02xjiLMlh6qAJFwJ0=",
|
|
"MEUCIHQMI9V89fSU9leOGQLr7cCTY56Vuc44OkxpLVWZUmojAiEAtcrJp7E50Id6SdEqFVtstjUp+rpZSpu3Vzhgwff94+E=",
|
|
"MEUCIFzPM6VC8fzEEX5wcq8D+LOQirjg1lDq7qqbo+i0P+dMAiEA4Spe3bGJdyTUGumjhc/Qosh9TDQnRkWQ9c0S2GwEFbA=",
|
|
},
|
|
},
|
|
{
|
|
name: "Test3",
|
|
publicKeyB64: "BGD4KpyqndHf5CTpAlZXTubZXaaoqac4LJ0QNUlS8rWjOwh8frmZTsAD1C6ps5iB5aZt5lc/X8LGgMu0334plGg=",
|
|
plaintextB64: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEigUJp7M4QumQ7r+xgsQqgNCsxFVaOz30EslGdi+lmN0DcX7RKAHCldU96JRj4A/AKxYOeN/Fb7VdVb7Wy1w3dg==",
|
|
signatures: []string{
|
|
"MEYCIQDA5DNoHDj5vX6pvtxRcu8HJnB4sDE7tMvOkKz+F8roGAIhAPzSWhOtE4sT3nCF7rcH0SQXmGWwHbCgplOOnnQh+EmP",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Logf("Testing %s", testCase.name)
|
|
|
|
// Parse the public key
|
|
t.Logf("Step 1: Parsing ECDSA P-256 public key for %s", testCase.name)
|
|
|
|
// Handle different key formats
|
|
var publicKey interface{}
|
|
var err error
|
|
|
|
// Try parsing as standard PKIX first
|
|
publicKey, err = parsePublicKey(testCase.publicKeyB64, "ecdsa-p256")
|
|
if err != nil {
|
|
// If PKIX parsing fails, try raw point format (second test case)
|
|
t.Errorf("PKIX parsing failed, trying raw point format: %v", err)
|
|
return
|
|
}
|
|
|
|
ecdsaKey, ok := publicKey.(*ecdsa.PublicKey)
|
|
if !ok {
|
|
t.Fatal("Parsed key is not ECDSA")
|
|
}
|
|
|
|
// Verify the curve
|
|
if ecdsaKey.Curve != elliptic.P256() {
|
|
t.Fatal("Key is not P-256 curve")
|
|
}
|
|
t.Logf("✓ Successfully parsed ECDSA P-256 public key for %s", testCase.name)
|
|
|
|
// Test signature verification
|
|
t.Logf("Step 2: Testing signature verification for %s", testCase.name)
|
|
successCount := 0
|
|
|
|
for i, sigB64 := range testCase.signatures {
|
|
t.Logf("Testing signature %d: %s", i+1, sigB64)
|
|
|
|
// Test using the main verifySignature function
|
|
sigBytes, err := base64.StdEncoding.DecodeString(sigB64)
|
|
if err != nil {
|
|
t.Errorf("Signature %d: Failed to decode signature: %v", i+1, err)
|
|
continue
|
|
}
|
|
|
|
// Test using the main verifySignature function
|
|
plainBytes, err := base64.StdEncoding.DecodeString(testCase.plaintextB64)
|
|
if err != nil {
|
|
t.Errorf("Signature %d: Failed to decode plaintextB64: %v", i+1, err)
|
|
continue
|
|
}
|
|
|
|
// Verify using the main verifySignature function
|
|
isValid := verifySignature(ecdsaKey, plainBytes, sigBytes)
|
|
if isValid {
|
|
t.Logf("✓ Signature %d verified successfully using verifySignature()", i+1)
|
|
successCount++
|
|
} else {
|
|
t.Logf("✗ Signature %d failed verification using verifySignature()", i+1)
|
|
}
|
|
}
|
|
|
|
t.Logf("Verification complete for %s: %d/%d signatures verified successfully", testCase.name, successCount, len(testCase.signatures))
|
|
|
|
if successCount == 0 {
|
|
t.Errorf("No signatures were successfully verified for %s - this may indicate a format issue", testCase.name)
|
|
}
|
|
t.Log("---")
|
|
}
|
|
}
|
|
|
|
// Test RSA-2048 PSS signature verification with provided test data
|
|
func TestRSA2048PSSSignatureVerification(t *testing.T) {
|
|
t.Log("Testing RSA-2048 PSS signature verification with provided test data")
|
|
|
|
// Test data sets
|
|
testCases := []struct {
|
|
name string
|
|
publicKeyB64 string
|
|
plaintextB64 string
|
|
signatures []string
|
|
}{
|
|
{
|
|
name: "Windows",
|
|
publicKeyB64: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3n0ussUHvZhH1nBZiWEka3OL6OFo7P+jXn+oaOkG+mloxG7JMmnp943z/z5rWvUNN6kZz2ZZeQ+k+ezBZKKvvI+n4ZP5IkgJ/I1nPJzRLKb79OgZATm4Bo/hhQIDdmcsHid7Ajmh+9PoqUwOcX/pZ6FFdSvw/cQc2SB38b5ghpCx3dpUrAfZUV1U3eC1uUr7KiyRm8Dj1hPg4ri9jJhqB4ktr0FjLF43kUlBmZzoNsKq9WcxukF/aLAAgYBBC/d0/FIBRemAgLWJWNm5j45aE0dmKFLfoz2hH4TG4mXKNljbc6O0dQUnM+xMkmhC5FrAXOo3YtZw8ooaVeALPjBCWwIDAQAB",
|
|
plaintextB64: "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiH3HbpFLTj27XqObpHeJKXW6j3TTwhX2o2LAheAmtBQU/Qgn/4DTeMlRh0tweqFno1QLhQ2Nu4QlpqmsiegscQ==",
|
|
signatures: []string{
|
|
"eKpBcP5DFWEMONxKk8iAyb5pabBppZVgBBT2Ftm9OmtQkh+bCPLGJM6ILVi6Tg3VafbBFPjwNERXSwfXbUsiP6ca8ijXKp7aWYdBu4gtRVbzoj6gr47jo3A38cMbfcm7AEpQfboovT6f0wUPXfnN2vEocprJM8vZ/BC3fmjNL8R5m3+QRY+y9b3Mu8zCr/rTLw8aflz7b7r2Nb+a2kkFLgdk1tgJTz+/gUTU/N+txVDyjFcdhWLY18p96D0PDVCgvYXIFstbF+VVZVSTAOSlg1QCP/JCEgMWrt1/cLimLr8hFXv0kAL2x4/V7C6KkZk7Z7BFxQbP76lpXtp5rTJnZw==",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Logf("Testing %s", testCase.name)
|
|
|
|
// Parse the public key
|
|
t.Logf("Step 1: Parsing RSA-2048 PSS public key for %s", testCase.name)
|
|
|
|
// Handle different key formats
|
|
var publicKey interface{}
|
|
var err error
|
|
|
|
// Try parsing as standard PKIX first
|
|
publicKey, err = parsePublicKey(testCase.publicKeyB64, "rsa-2048-pss")
|
|
if err != nil {
|
|
// If PKIX parsing fails, try raw point format (second test case)
|
|
t.Errorf("PKIX parsing failed, trying raw point format: %v", err)
|
|
return
|
|
}
|
|
|
|
rsaKey, ok := publicKey.(*rsa.PublicKey)
|
|
if !ok {
|
|
t.Fatal("Parsed key is not RSA")
|
|
}
|
|
|
|
// Test signature verification
|
|
t.Logf("Step 2: Testing signature verification for %s", testCase.name)
|
|
successCount := 0
|
|
|
|
for i, sigB64 := range testCase.signatures {
|
|
t.Logf("Testing signature %d: %s", i+1, sigB64)
|
|
|
|
// Test using the main verifySignature function
|
|
sigBytes, err := base64.StdEncoding.DecodeString(sigB64)
|
|
if err != nil {
|
|
t.Errorf("Signature %d: Failed to decode signature: %v", i+1, err)
|
|
continue
|
|
}
|
|
|
|
// Test using the main verifySignature function
|
|
plainBytes, err := base64.StdEncoding.DecodeString(testCase.plaintextB64)
|
|
if err != nil {
|
|
t.Errorf("Signature %d: Failed to decode plaintextB64: %v", i+1, err)
|
|
continue
|
|
}
|
|
|
|
// Verify using the main verifySignature function
|
|
isValid := verifySignature(rsaKey, plainBytes, sigBytes)
|
|
if isValid {
|
|
t.Logf("✓ Signature %d verified successfully using verifySignature()", i+1)
|
|
successCount++
|
|
} else {
|
|
t.Logf("✗ Signature %d failed verification using verifySignature()", i+1)
|
|
}
|
|
}
|
|
|
|
t.Logf("Verification complete for %s: %d/%d signatures verified successfully", testCase.name, successCount, len(testCase.signatures))
|
|
|
|
if successCount == 0 {
|
|
t.Errorf("No signatures were successfully verified for %s - this may indicate a format issue", testCase.name)
|
|
}
|
|
t.Log("---")
|
|
}
|
|
}
|