* Reverse time * Change time handling global * Remove debug functions * Remove *pgp methods
197 lines
5.2 KiB
Go
197 lines
5.2 KiB
Go
package crypto
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
|
|
"github.com/ProtonMail/gopenpgp/armor"
|
|
"github.com/ProtonMail/gopenpgp/constants"
|
|
|
|
"golang.org/x/crypto/openpgp"
|
|
"golang.org/x/crypto/openpgp/packet"
|
|
)
|
|
|
|
// IsKeyExpired checks whether the given (unarmored, binary) key is expired.
|
|
func IsKeyExpired(publicKey []byte) (bool, error) {
|
|
now := getNow()
|
|
pubKeyReader := bytes.NewReader(publicKey)
|
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
for _, e := range pubKeyEntries {
|
|
if _, ok := e.EncryptionKey(now); ok {
|
|
return false, nil
|
|
}
|
|
}
|
|
return true, errors.New("keys expired")
|
|
}
|
|
|
|
// IsArmoredKeyExpired checks whether the given armored key is expired.
|
|
func IsArmoredKeyExpired(publicKey string) (bool, error) {
|
|
rawPubKey, err := armor.Unarmor(publicKey)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return IsKeyExpired(rawPubKey)
|
|
}
|
|
|
|
func generateKey(
|
|
name, email, passphrase, keyType string,
|
|
bits int,
|
|
prime1, prime2, prime3, prime4 []byte,
|
|
) (string, error) {
|
|
if len(email) <= 0 {
|
|
return "", errors.New("invalid email format")
|
|
}
|
|
|
|
if len(name) <= 0 {
|
|
return "", errors.New("invalid name format")
|
|
}
|
|
|
|
comments := ""
|
|
|
|
cfg := &packet.Config{
|
|
Algorithm: packet.PubKeyAlgoRSA,
|
|
RSABits: bits,
|
|
Time: getTimeGenerator(),
|
|
DefaultHash: crypto.SHA256,
|
|
DefaultCipher: packet.CipherAES256,
|
|
}
|
|
|
|
if keyType == "x25519" {
|
|
cfg.Algorithm = packet.PubKeyAlgoEdDSA
|
|
}
|
|
|
|
if prime1 != nil && prime2 != nil && prime3 != nil && prime4 != nil {
|
|
var bigPrimes [4]*big.Int
|
|
bigPrimes[0] = new(big.Int)
|
|
bigPrimes[0].SetBytes(prime1)
|
|
bigPrimes[1] = new(big.Int)
|
|
bigPrimes[1].SetBytes(prime2)
|
|
bigPrimes[2] = new(big.Int)
|
|
bigPrimes[2].SetBytes(prime3)
|
|
bigPrimes[3] = new(big.Int)
|
|
bigPrimes[3].SetBytes(prime4)
|
|
|
|
cfg.RSAPrimes = bigPrimes[:]
|
|
}
|
|
|
|
newEntity, err := openpgp.NewEntity(name, comments, email, cfg)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if err := newEntity.SelfSign(nil); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
rawPwd := []byte(passphrase)
|
|
if newEntity.PrivateKey != nil && !newEntity.PrivateKey.Encrypted {
|
|
if err := newEntity.PrivateKey.Encrypt(rawPwd); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
for _, sub := range newEntity.Subkeys {
|
|
if sub.PrivateKey != nil && !sub.PrivateKey.Encrypted {
|
|
if err := sub.PrivateKey.Encrypt(rawPwd); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
}
|
|
|
|
w := bytes.NewBuffer(nil)
|
|
if err := newEntity.SerializePrivateNoSign(w, nil); err != nil {
|
|
return "", err
|
|
}
|
|
serialized := w.Bytes()
|
|
return armor.ArmorWithType(serialized, constants.PrivateKeyHeader)
|
|
}
|
|
|
|
// GenerateRSAKeyWithPrimes generates a RSA key using the given primes.
|
|
func GenerateRSAKeyWithPrimes(
|
|
name, email, passphrase string,
|
|
bits int,
|
|
primeone, primetwo, primethree, primefour []byte,
|
|
) (string, error) {
|
|
return generateKey(name, email, passphrase, "rsa", bits, primeone, primetwo, primethree, primefour)
|
|
}
|
|
|
|
// GenerateKey generates a key of the given keyType ("rsa" or "x25519").
|
|
// If keyType is "rsa", bits is the RSA bitsize of the key.
|
|
// If keyType is "x25519" bits is unused.
|
|
func GenerateKey(name, email, passphrase, keyType string, bits int) (string, error) {
|
|
return generateKey(name, email, passphrase, keyType, bits, nil, nil, nil, nil)
|
|
}
|
|
|
|
// UpdatePrivateKeyPassphrase decrypts the given armored privateKey with oldPassphrase,
|
|
// re-encrypts it with newPassphrase, and returns the new armored key.
|
|
func UpdatePrivateKeyPassphrase(
|
|
privateKey string, oldPassphrase string, newPassphrase string,
|
|
) (string, error) {
|
|
privKey := strings.NewReader(privateKey)
|
|
privKeyEntries, err := openpgp.ReadArmoredKeyRing(privKey)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
oldrawPwd := []byte(oldPassphrase)
|
|
newRawPwd := []byte(newPassphrase)
|
|
w := bytes.NewBuffer(nil)
|
|
for _, e := range privKeyEntries {
|
|
if e.PrivateKey != nil && e.PrivateKey.Encrypted {
|
|
if err := e.PrivateKey.Decrypt(oldrawPwd); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
if e.PrivateKey != nil && !e.PrivateKey.Encrypted {
|
|
if err := e.PrivateKey.Encrypt(newRawPwd); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
for _, sub := range e.Subkeys {
|
|
if sub.PrivateKey != nil && sub.PrivateKey.Encrypted {
|
|
if err := sub.PrivateKey.Decrypt(oldrawPwd); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
if sub.PrivateKey != nil && !sub.PrivateKey.Encrypted {
|
|
if err := sub.PrivateKey.Encrypt(newRawPwd); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
}
|
|
if err := e.SerializePrivateNoSign(w, nil); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
serialized := w.Bytes()
|
|
return armor.ArmorWithType(serialized, constants.PrivateKeyHeader)
|
|
}
|
|
|
|
// PrintFingerprints is a debug helper function that prints the key and subkey fingerprints.
|
|
func PrintFingerprints(pubKey string) (string, error) {
|
|
pubKeyReader := strings.NewReader(pubKey)
|
|
entries, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for _, e := range entries {
|
|
for _, subKey := range e.Subkeys {
|
|
if !subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications {
|
|
fmt.Println("SubKey:" + hex.EncodeToString(subKey.PublicKey.Fingerprint[:]))
|
|
}
|
|
}
|
|
fmt.Println("PrimaryKey:" + hex.EncodeToString(e.PrimaryKey.Fingerprint[:]))
|
|
}
|
|
return "", nil
|
|
}
|