Пример использования RSA

8 minute read

Перевод статьи "Golang & Cryptography. RSA sample"

Как вы вероятно знаете, большинство самых используемых криптографических библиотек написано на С (или С++). Go весь пропитан духом C, он небольшой но весьма эффективный язык с удобной инфраструктурой и такими низкоуровневыми возможностями, как указатели. Кроме того, Go предоставляет широкий набор фичей для более высокоуровневого программирования. Меньше кода, быстрее компиляция, быстрое исполнение - это философия Go.

Все это делает Go замечательным языком для написания криптографического приложения.

В этом примере мы научимся использовать функции из пакета crypto/rsa.

Предположим, что Лена хочет отправить секретное сообщение Алисе. Для этого нужно выполнить ряд действий.

  1. Для начала, у Лены и Алисы должны быть пары ключей. Одни ключ приватный, второй публичный.
package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "fmt"
    "os"
)

func main() {
    lenaPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)

    if err != nil {
        fmt.Println(err.Error)
        os.Exit(1)
    }

    lenaPublicKey := &lenaPrivateKey.PublicKey

    alisaPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)

    if err != nil {
        fmt.Println(err.Error)
        os.Exit(1)
    }

    alisaPublicKey := &alisaPrivateKey.PublicKey

    fmt.Println("Private Key : ", lenaPrivateKey)
    fmt.Println("Public key ", lenaPublicKey)
    fmt.Println("Private Key : ", alisaPrivateKey)
    fmt.Println("Public key ", alisaPublicKey)

}
  1. Лене необходимо зашифровать свое сообщение публичным ключем Алисы.
message := []byte("the code must be like a piece of music")  
label := []byte("")  
hash := sha256.New()

ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, alisaPublicKey, message, label 

if err != nil {  
    fmt.Println(err)
    os.Exit(1)
}

fmt.Printf("OAEP encrypted [%s] to \n[%x]\n", string(message), ciphertext)  

Стоит обратить внимание, что OAEP этот рекомендуемый стандарт, определяющий количество байтов, добавляемых к исходной записи(padding). Стандарт PKCS1v15 стоит использовать только для поддержки старых версий протоколов.

  1. Далее, Лена должна подписать сообщение Алисы с помощью своего приватного ключа. Это позволит Алисе проверить отправителя сообщения с помощью Лениного публичного ключа и убедится что его отправила именно Лена.
var opts rsa.PSSOptions  
opts.SaltLength = rsa.PSSSaltLengthAuto // for simple example  
PSSmessage := message  
newhash := crypto.SHA256  
pssh := newhash.New()  
pssh.Write(PSSmessage)  
hashed := pssh.Sum(nil)

signature, err := rsa.SignPSS(rand.Reader, lenaPrivateKey, newhash, hashed, &opts)

if err != nil {  
    fmt.Println(err)
    os.Exit(1)
}

fmt.Printf("PSS Signature : %x\n", signature)  

В этом случае мы выбираем PSS алгоритм. PKCS1v15 стоит использовать только для поддержки старых версий протокола.

  1. Теперь у Лены есть все части сообщения для отправки его Алисе.
[ciphertext, signature]
  1. Когда Алиса получает сообщение, первое что она должна сделать, это расшифровать его.
plainText, err := rsa.DecryptOAEP(hash, rand.Reader, alisaPrivateKey, ciphertext, label)

if err != nil {  
    fmt.Println(err)
    os.Exit(1)
}

fmt.Printf("OAEP decrypted [%x] to \n[%s]\n", ciphertext, plainText)  
  1. И последний шаг, это проверка отправителя. Действительно ли сообщение отправила Лена:
err = rsa.VerifyPSS(lenaPublicKey, newhash, hashed, signature, &opts)

if err != nil {  
    fmt.Println("Who are U? Verify Signature failed")
    os.Exit(1)
} else {
    fmt.Println("Verify Signature successful")
}

Таким образом, Алиса получила сообщение, проверила отправителя и она просто вне себя от радости!

В рамках этого небольшого туториала мы создали репозиторий на GitHub с примерами кода, который вы можете использовать: github.com/brainattica/Golang-RSA-sample

В нашем следующем туториале мы попробуем экспортировать и импортировать пары RSA ключей в PEM формат.