Пакет crypto/ecdsa
Пакет crypto/ecdsa реализует алгоритм цифровой подписи
на эллиптических кривых (ECDSA) согласно стандарту FIPS 186-4.
Он предоставляет функции для генерации ключевых пар, создания
цифровых подписей и их верификации. Пакет использует кривые из
пакета crypto/elliptic, такие как P-256, P-384 и P-521.
Генерация ключевой пары
Функция GenerateKey создает новую пару закрытого и
открытого ключей. В качестве первого параметра она принимает
эллиптическую кривую, а вторым параметром - источник случайных
чисел. Возвращает указатель на структуру PrivateKey.
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
)
func main() {
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Private key: %x\n", privateKey.D)
fmt.Printf("Public key X: %x\n", privateKey.PublicKey.X)
fmt.Printf("Public key Y: %x\n", privateKey.PublicKey.Y)
}
Результат выполнения кода:
"Private key: 2f3e5a7b9c1d..."
"Public key X: 4a6b8c0d1e2f..."
"Public key Y: 3b5d7f9a1c3e..."
Функция GenerateKey возвращает закрытый ключ, который
содержит открытый ключ в своем составе. Закрытый ключ должен
храниться в секрете, а открытый ключ можно распространять.
Создание цифровой подписи
Функция Sign создает цифровую подпись для сообщения.
В качестве параметров она принимает источник случайных чисел,
закрытый ключ и хеш сообщения. Возвращает пару чисел r и s,
которые являются компонентами подписи.
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
)
func main() {
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
message := []byte("Hello, ECDSA!")
hash := sha256.Sum256(message)
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:])
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("r: %x\n", r)
fmt.Printf("s: %x\n", s)
}
Результат выполнения кода:
"r: 3b6a7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b"
"s: 7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d"
Функция Sign возвращает компоненты подписи r и s.
Они представлены в виде больших чисел (*big.Int).
Обе компоненты должны быть переданы вместе с сообщением для
верификации.
Верификация подписи
Функция Verify проверяет валидность цифровой подписи.
Она принимает открытый ключ, хеш сообщения и компоненты подписи r и s.
Возвращает true, если подпись действительна, иначе false.
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
)
func main() {
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
message := []byte("Hello, ECDSA!")
hash := sha256.Sum256(message)
r, s, _ := ecdsa.Sign(rand.Reader, privateKey, hash[:])
publicKey := privateKey.PublicKey
isValid := ecdsa.Verify(&publicKey, hash[:], r, s)
fmt.Println("Signature valid:", isValid)
}
Результат выполнения кода:
"Signature valid: true"
Функция Verify проверяет, что подпись создана с
использованием закрытого ключа, соответствующего переданному
открытому ключу. Это гарантирует подлинность сообщения.
Работа с ASN.1 форматом
Пакет предоставляет функции SignASN1 и VerifyASN1
для работы с подписями в формате ASN.1 DER. Это стандартный
формат для обмена цифровыми подписями.
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
)
func main() {
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
message := []byte("Hello, ECDSA!")
hash := sha256.Sum256(message)
signature, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:])
if err != nil {
fmt.Println(err)
return
}
publicKey := privateKey.PublicKey
isValid := ecdsa.VerifyASN1(&publicKey, hash[:], signature)
fmt.Printf("Signature: %x\n", signature)
fmt.Println("Valid:", isValid)
}
Результат выполнения кода:
"Signature: 3046022100a1b2c3d4e5f6..."
"Valid: true"
Функции SignASN1 и VerifyASN1 работают с
подписями в стандартном формате ASN.1 DER. Это удобно для
хранения и передачи подписей через сети.
Практический пример
Полный пример использования пакета crypto/ecdsa для
подписи и верификации сообщения:
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
"log"
)
func main() {
// Генерация ключевой пары
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}
// Данные для подписи
message := []byte("Document to sign")
hash := sha256.Sum256(message)
// Создание подписи
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:])
if err != nil {
log.Fatal(err)
}
// Верификация подписи
publicKey := privateKey.PublicKey
isValid := ecdsa.Verify(&publicKey, hash[:], r, s)
if isValid {
fmt.Println("Success: Signature is valid")
} else {
fmt.Println("Error: Invalid signature")
}
}
Результат выполнения кода:
"Success: Signature is valid"
В этом примере показан полный цикл работы с ECDSA: генерация ключей, создание подписи для хеша сообщения и ее верификация.
Смотрите также
-
пакет
crypto/rsa,
который реализует алгоритм RSA для шифрования и подписи -
пакет
crypto/ed25519,
который реализует схему подписи Ed25519 -
пакет
crypto/elliptic,
который предоставляет эллиптические кривые -
пакет
crypto/hmac,
который реализует HMAC для аутентификации сообщений