2018-09-11 11:09:28 +02:00
|
|
|
package crypto
|
2018-06-04 16:05:14 -07:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2018-06-06 14:05:57 -07:00
|
|
|
"crypto"
|
2018-11-05 22:55:45 +01:00
|
|
|
"encoding/base64"
|
2018-06-04 16:05:14 -07:00
|
|
|
"encoding/hex"
|
|
|
|
|
"errors"
|
2018-11-05 22:55:45 +01:00
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"math/big"
|
2018-11-22 10:53:14 +01:00
|
|
|
"runtime"
|
2018-11-05 22:55:45 +01:00
|
|
|
"strings"
|
2019-03-07 16:56:12 +01:00
|
|
|
"time"
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2019-05-13 14:07:18 +02:00
|
|
|
"github.com/ProtonMail/gopenpgp/armor"
|
|
|
|
|
"github.com/ProtonMail/gopenpgp/constants"
|
|
|
|
|
"github.com/ProtonMail/gopenpgp/models"
|
2019-03-07 16:56:12 +01:00
|
|
|
|
2018-06-04 16:05:14 -07:00
|
|
|
"golang.org/x/crypto/openpgp"
|
|
|
|
|
"golang.org/x/crypto/openpgp/packet"
|
|
|
|
|
)
|
|
|
|
|
|
2019-03-07 16:56:12 +01:00
|
|
|
// SymmetricKey stores a decrypted session key.
|
2018-11-05 22:55:45 +01:00
|
|
|
type SymmetricKey struct {
|
|
|
|
|
// The clear base64-encoded key.
|
|
|
|
|
Key []byte
|
|
|
|
|
// The algorithm used by this key.
|
|
|
|
|
Algo string
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 16:56:12 +01:00
|
|
|
// SymmetricallyEncryptedTag is 18 with the 2 highest order bits set to 1
|
2018-11-05 22:55:45 +01:00
|
|
|
const SymmetricallyEncryptedTag = 210
|
|
|
|
|
|
|
|
|
|
var symKeyAlgos = map[string]packet.CipherFunction{
|
2019-05-14 14:42:38 +00:00
|
|
|
constants.ThreeDES: packet.Cipher3DES,
|
|
|
|
|
constants.TripleDES: packet.Cipher3DES,
|
|
|
|
|
constants.CAST5: packet.CipherCAST5,
|
|
|
|
|
constants.AES128: packet.CipherAES128,
|
|
|
|
|
constants.AES192: packet.CipherAES192,
|
|
|
|
|
constants.AES256: packet.CipherAES256,
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:42:38 +00:00
|
|
|
// GetCipherFunc returns function corresponding to an algorithm used in
|
|
|
|
|
// this SymmetricKey
|
2018-11-05 22:55:45 +01:00
|
|
|
func (sk *SymmetricKey) GetCipherFunc() packet.CipherFunction {
|
|
|
|
|
cf, ok := symKeyAlgos[sk.Algo]
|
|
|
|
|
if ok {
|
|
|
|
|
return cf
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 17:03:16 +01:00
|
|
|
panic("pm-crypto: unsupported cipher function: " + sk.Algo)
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-03-07 16:56:12 +01:00
|
|
|
// GetBase64Key returns a key as base64 encoded string
|
2018-11-05 22:55:45 +01:00
|
|
|
func (sk *SymmetricKey) GetBase64Key() string {
|
|
|
|
|
return base64.StdEncoding.EncodeToString(sk.Key)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newSymmetricKey(ek *packet.EncryptedKey) *SymmetricKey {
|
|
|
|
|
var algo string
|
|
|
|
|
for k, v := range symKeyAlgos {
|
|
|
|
|
if v == ek.CipherFunc {
|
|
|
|
|
algo = k
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if algo == "" {
|
2019-03-07 17:03:16 +01:00
|
|
|
panic(fmt.Sprintf("pm-crypto: unsupported cipher function: %v", ek.CipherFunc))
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &SymmetricKey{
|
|
|
|
|
Key: ek.Key, //base64.StdEncoding.EncodeToString(ek.Key),
|
|
|
|
|
Algo: algo,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 12:33:01 +00:00
|
|
|
// DecryptAttKey and returns a symmetric key
|
2018-11-05 22:55:45 +01:00
|
|
|
func DecryptAttKey(kr *KeyRing, keyPacket string) (key *SymmetricKey, err error) {
|
|
|
|
|
r := base64.NewDecoder(base64.StdEncoding, strings.NewReader(keyPacket))
|
|
|
|
|
packets := packet.NewReader(r)
|
|
|
|
|
|
|
|
|
|
var p packet.Packet
|
|
|
|
|
if p, err = packets.Next(); err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ek := p.(*packet.EncryptedKey)
|
|
|
|
|
|
|
|
|
|
var decryptErr error
|
|
|
|
|
for _, key := range kr.entities.DecryptionKeys() {
|
|
|
|
|
priv := key.PrivateKey
|
|
|
|
|
if priv.Encrypted {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if decryptErr != nil {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = fmt.Errorf("pm-crypto: cannot decrypt encrypted key packet: %v", decryptErr)
|
2018-11-05 22:55:45 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key = newSymmetricKey(ek)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 14:23:38 +01:00
|
|
|
// SeparateKeyAndData from packets in a pgp session
|
2019-05-14 14:42:38 +00:00
|
|
|
func SeparateKeyAndData(
|
|
|
|
|
kr *KeyRing, r io.Reader,
|
|
|
|
|
estimatedLength, garbageCollector int,
|
|
|
|
|
) (outSplit *models.EncryptedSplit, err error) {
|
2018-11-22 10:53:14 +01:00
|
|
|
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
|
2018-11-05 22:55:45 +01:00
|
|
|
packets := packet.NewReader(r)
|
|
|
|
|
outSplit = &models.EncryptedSplit{}
|
2018-11-22 10:53:14 +01:00
|
|
|
gcCounter := 0
|
2018-11-05 22:55:45 +01:00
|
|
|
|
|
|
|
|
// Save encrypted key and signature apart
|
|
|
|
|
var ek *packet.EncryptedKey
|
|
|
|
|
var decryptErr error
|
|
|
|
|
for {
|
|
|
|
|
var p packet.Packet
|
|
|
|
|
if p, err = packets.Next(); err == io.EOF {
|
|
|
|
|
err = nil
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
switch p := p.(type) {
|
|
|
|
|
case *packet.EncryptedKey:
|
|
|
|
|
// We got an encrypted key. Try to decrypt it with each available key
|
|
|
|
|
if ek != nil && ek.Key != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
ek = p
|
2018-06-04 16:05:14 -07:00
|
|
|
|
2018-11-05 22:55:45 +01:00
|
|
|
if kr != nil {
|
|
|
|
|
for _, key := range kr.entities.DecryptionKeys() {
|
|
|
|
|
priv := key.PrivateKey
|
|
|
|
|
if priv.Encrypted {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case *packet.SymmetricallyEncrypted:
|
2018-11-22 10:53:14 +01:00
|
|
|
// The code below is optimized to not
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
|
// 2^16 is an estimation of the size difference between input and output, the size difference is most probably
|
|
|
|
|
// 16 bytes at a maximum though.
|
|
|
|
|
// We need to avoid triggering a grow from the system as this will allocate too much memory causing problems
|
|
|
|
|
// in low-memory environments
|
|
|
|
|
b.Grow(1<<16 + estimatedLength)
|
|
|
|
|
// empty encoded length + start byte
|
|
|
|
|
b.Write(make([]byte, 6))
|
|
|
|
|
b.WriteByte(byte(1))
|
|
|
|
|
actualLength := 1
|
|
|
|
|
block := make([]byte, 128)
|
|
|
|
|
for {
|
|
|
|
|
n, err := p.Contents.Read(block)
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
b.Write(block[:n])
|
|
|
|
|
actualLength += n
|
|
|
|
|
gcCounter += n
|
|
|
|
|
if gcCounter > garbageCollector && garbageCollector > 0 {
|
|
|
|
|
runtime.GC()
|
|
|
|
|
gcCounter = 0
|
|
|
|
|
}
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 10:53:14 +01:00
|
|
|
// quick encoding
|
|
|
|
|
symEncryptedData := b.Bytes()
|
|
|
|
|
if actualLength < 192 {
|
|
|
|
|
symEncryptedData[4] = byte(210)
|
|
|
|
|
symEncryptedData[5] = byte(actualLength)
|
|
|
|
|
symEncryptedData = symEncryptedData[4:]
|
|
|
|
|
} else if actualLength < 8384 {
|
|
|
|
|
actualLength = actualLength - 192
|
|
|
|
|
symEncryptedData[3] = byte(210)
|
|
|
|
|
symEncryptedData[4] = 192 + byte(actualLength>>8)
|
|
|
|
|
symEncryptedData[5] = byte(actualLength)
|
|
|
|
|
symEncryptedData = symEncryptedData[3:]
|
|
|
|
|
} else {
|
|
|
|
|
symEncryptedData[0] = byte(210)
|
|
|
|
|
symEncryptedData[1] = byte(255)
|
|
|
|
|
symEncryptedData[2] = byte(actualLength >> 24)
|
|
|
|
|
symEncryptedData[3] = byte(actualLength >> 16)
|
|
|
|
|
symEncryptedData[4] = byte(actualLength >> 8)
|
|
|
|
|
symEncryptedData[5] = byte(actualLength)
|
|
|
|
|
}
|
2018-11-05 22:55:45 +01:00
|
|
|
|
|
|
|
|
outSplit.DataPacket = symEncryptedData
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if decryptErr != nil {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = fmt.Errorf("pm-crypto: cannot decrypt encrypted key packet: %v", decryptErr)
|
2019-05-13 12:42:29 +00:00
|
|
|
return nil, err
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
if ek == nil {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = errors.New("pm-crypto: packets don't include an encrypted key packet")
|
2019-05-13 12:42:29 +00:00
|
|
|
return nil, err
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if kr == nil {
|
|
|
|
|
var buf bytes.Buffer
|
2019-05-13 12:42:29 +00:00
|
|
|
if err := ek.Serialize(&buf); err != nil {
|
|
|
|
|
err = fmt.Errorf("pm-crypto: cannot serialize encrypted key: %v", err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-11-05 22:55:45 +01:00
|
|
|
outSplit.KeyPacket = buf.Bytes()
|
|
|
|
|
} else {
|
|
|
|
|
key := newSymmetricKey(ek)
|
|
|
|
|
outSplit.KeyPacket = key.Key
|
|
|
|
|
outSplit.Algo = key.Algo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return outSplit, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetKey encrypts the provided key.
|
|
|
|
|
func SetKey(kr *KeyRing, symKey *SymmetricKey) (packets string, err error) {
|
|
|
|
|
b := &bytes.Buffer{}
|
|
|
|
|
w := base64.NewEncoder(base64.StdEncoding, b)
|
|
|
|
|
|
|
|
|
|
cf := symKey.GetCipherFunc()
|
|
|
|
|
|
|
|
|
|
if len(kr.entities) == 0 {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = fmt.Errorf("pm-crypto: cannot set key: key ring is empty")
|
2018-11-05 22:55:45 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var pub *packet.PublicKey
|
|
|
|
|
for _, e := range kr.entities {
|
|
|
|
|
for _, subKey := range e.Subkeys {
|
|
|
|
|
if !subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications {
|
|
|
|
|
pub = subKey.PublicKey
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if pub == nil && len(e.Identities) > 0 {
|
|
|
|
|
var i *openpgp.Identity
|
|
|
|
|
for _, i = range e.Identities {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptStorage || i.SelfSignature.FlagEncryptCommunications {
|
|
|
|
|
pub = e.PrimaryKey
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if pub != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if pub == nil {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = fmt.Errorf("pm-crypto: cannot set key: no public key available")
|
2019-05-14 14:42:38 +00:00
|
|
|
return "", err
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = packet.SerializeEncryptedKey(w, pub, cf, symKey.Key, nil); err != nil {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = fmt.Errorf("pm-crypto: cannot set key: %v", err)
|
2019-05-14 14:42:38 +00:00
|
|
|
return "", err
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = w.Close(); err != nil {
|
2019-03-07 17:03:16 +01:00
|
|
|
err = fmt.Errorf("pm-crypto: cannot set key: %v", err)
|
2019-05-14 14:42:38 +00:00
|
|
|
return "", err
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:42:38 +00:00
|
|
|
return b.String(), nil
|
2018-11-05 22:55:45 +01:00
|
|
|
}
|
|
|
|
|
|
2019-03-07 16:56:12 +01:00
|
|
|
// IsKeyExpiredBin checks if the given key is expired. Input in binary format
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) IsKeyExpiredBin(publicKey []byte) (bool, error) {
|
|
|
|
|
now := pgp.getNow()
|
2018-06-04 16:05:14 -07:00
|
|
|
pubKeyReader := bytes.NewReader(publicKey)
|
|
|
|
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return true, err
|
|
|
|
|
}
|
|
|
|
|
candidateSubkey := -1
|
|
|
|
|
for _, e := range pubKeyEntries {
|
|
|
|
|
var maxTime time.Time
|
|
|
|
|
for i, subkey := range e.Subkeys {
|
|
|
|
|
if subkey.Sig.FlagsValid &&
|
|
|
|
|
subkey.Sig.FlagEncryptCommunications &&
|
|
|
|
|
subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
|
2019-04-27 07:22:10 +02:00
|
|
|
!subkey.PublicKey.KeyExpired(subkey.Sig, now) &&
|
2018-06-04 16:05:14 -07:00
|
|
|
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
|
|
|
|
|
candidateSubkey = i
|
|
|
|
|
maxTime = subkey.Sig.CreationTime
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if candidateSubkey != -1 {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we don't have any candidate subkeys for encryption and
|
|
|
|
|
// the primary key doesn't have any usage metadata then we
|
|
|
|
|
// assume that the primary key is ok. Or, if the primary key is
|
|
|
|
|
// marked as ok to encrypt to, then we can obviously use it.
|
|
|
|
|
var firstIdentity *openpgp.Identity
|
|
|
|
|
for _, ident := range e.Identities {
|
|
|
|
|
if firstIdentity == nil {
|
|
|
|
|
firstIdentity = ident
|
|
|
|
|
}
|
|
|
|
|
if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
|
|
|
|
|
firstIdentity = ident
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if firstIdentity != nil {
|
|
|
|
|
i := firstIdentity
|
|
|
|
|
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
|
|
|
|
|
e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
|
2019-04-27 07:22:10 +02:00
|
|
|
!e.PrimaryKey.KeyExpired(i.SelfSignature, now) {
|
2018-06-04 16:05:14 -07:00
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true, errors.New("keys expired")
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 22:55:45 +01:00
|
|
|
const (
|
|
|
|
|
ok = 0
|
|
|
|
|
notSigned = 1
|
|
|
|
|
noVerifier = 2
|
|
|
|
|
failed = 3
|
|
|
|
|
)
|
|
|
|
|
|
2019-03-07 16:56:12 +01:00
|
|
|
// IsKeyExpired checks if the given key is expired. Input in armored format
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) IsKeyExpired(publicKey string) (bool, error) {
|
2018-09-19 11:52:14 +02:00
|
|
|
rawPubKey, err := armor.Unarmor(publicKey)
|
2018-06-04 16:05:14 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
2019-05-14 18:05:01 +02:00
|
|
|
return pgp.IsKeyExpiredBin(rawPubKey)
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) generateKey(
|
2019-05-14 14:42:38 +00:00
|
|
|
userName, domain, passphrase, keyType string,
|
|
|
|
|
bits int,
|
|
|
|
|
prime1, prime2, prime3, prime4 []byte,
|
|
|
|
|
) (string, error) {
|
2018-06-04 16:05:14 -07:00
|
|
|
if len(userName) <= 0 {
|
2019-05-13 12:33:01 +00:00
|
|
|
return "", errors.New("invalid user name format")
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
2018-06-05 11:40:42 -07:00
|
|
|
var email = userName
|
|
|
|
|
|
|
|
|
|
if len(domain) > 0 {
|
|
|
|
|
email = email + "@" + domain
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
2018-06-05 11:40:42 -07:00
|
|
|
|
2018-06-04 16:05:14 -07:00
|
|
|
comments := ""
|
|
|
|
|
|
2018-06-06 14:05:57 -07:00
|
|
|
cfg := &packet.Config{
|
2018-09-11 11:09:28 +02:00
|
|
|
Algorithm: packet.PubKeyAlgoRSA,
|
2018-06-06 14:05:57 -07:00
|
|
|
RSABits: bits,
|
2019-05-14 18:05:01 +02:00
|
|
|
Time: pgp.getTimeGenerator(),
|
2018-06-06 14:05:57 -07:00
|
|
|
DefaultHash: crypto.SHA256,
|
|
|
|
|
DefaultCipher: packet.CipherAES256,
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-19 11:28:37 +02:00
|
|
|
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[:]
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-04 16:05:14 -07:00
|
|
|
newEntity, err := openpgp.NewEntity(email, 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()
|
2019-03-07 16:56:12 +01:00
|
|
|
return armor.ArmorWithType(serialized, constants.PrivateKeyHeader)
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2019-03-07 16:56:12 +01:00
|
|
|
// GenerateRSAKeyWithPrimes generates RSA key with given primes.
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) GenerateRSAKeyWithPrimes(
|
2019-03-07 16:56:12 +01:00
|
|
|
userName, domain, passphrase string,
|
|
|
|
|
bits int,
|
|
|
|
|
primeone, primetwo, primethree, primefour []byte,
|
|
|
|
|
) (string, error) {
|
2019-05-14 18:05:01 +02:00
|
|
|
return pgp.generateKey(userName, domain, passphrase, "rsa", bits, primeone, primetwo, primethree, primefour)
|
2018-06-19 11:28:37 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-10 08:08:03 +02:00
|
|
|
// GenerateKey and generate primes
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) GenerateKey(userName, domain, passphrase, keyType string, bits int) (string, error) {
|
|
|
|
|
return pgp.generateKey(userName, domain, passphrase, keyType, bits, nil, nil, nil, nil)
|
2018-06-19 11:28:37 +02:00
|
|
|
}
|
2018-09-19 11:52:14 +02:00
|
|
|
|
2019-05-14 14:42:38 +00:00
|
|
|
// UpdatePrivateKeyPassphrase decrypts the given private key with oldPhrase and
|
|
|
|
|
// re-encrypts with the newPassphrase
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) UpdatePrivateKeyPassphrase(
|
2019-05-14 14:42:38 +00:00
|
|
|
privateKey string, oldPassphrase string, newPassphrase string,
|
|
|
|
|
) (string, error) {
|
2018-06-04 16:05:14 -07:00
|
|
|
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()
|
2019-03-07 16:56:12 +01:00
|
|
|
return armor.ArmorWithType(serialized, constants.PrivateKeyHeader)
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-13 12:33:01 +00:00
|
|
|
// CheckKey prints out the key and subkey fingerprint
|
2019-05-14 18:05:01 +02:00
|
|
|
func (pgp *GopenPGP) CheckKey(pubKey string) (string, error) {
|
2018-06-04 16:05:14 -07:00
|
|
|
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 {
|
2019-05-13 14:06:54 +00:00
|
|
|
fmt.Println("SubKey:" + hex.EncodeToString(subKey.PublicKey.Fingerprint[:]))
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-13 14:06:54 +00:00
|
|
|
fmt.Println("PrimaryKey:" + hex.EncodeToString(e.PrimaryKey.Fingerprint[:]))
|
2018-06-04 16:05:14 -07:00
|
|
|
}
|
|
|
|
|
return "", nil
|
|
|
|
|
}
|