Refactor api (#6)
* Refactor library, remove duplicates * Rebuild structure to use Messages and Signature models * Use PGPSplitMessage * Remove signature model * Various fixes * Add helpers with tests * Fixes, add some docs, add tests * Add attachment helpers * Add helpers Symmetric encryption * Edit docs + examples * Rename kr to keyRing * Various fixes for documentation * Edit JSON handling functions, add decrypt keyring via token * Add proposal changes doc * Fix CI * Drop *Message functions, join CleartextMessage and BinaryMessage * Change canonicalization and trimming only to text signatures * Add cleartextsignature, detach signature from message model, move helpers * Documentation, remove optional parameters * Move verification to separate model * Don't return message in VerifyDetached * Update table of contents in readme * Appease golint * Run go fmt * Rename Encrypt/DecryptMessageWithPassword to ..WithToken These functions shouldn't be used with user-provided passwords, as they don't do any key-stretching. * Change key generation usernames
This commit is contained in:
parent
82d49bf235
commit
e65ed17b41
34 changed files with 2573 additions and 1478 deletions
|
|
@ -6,26 +6,18 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/armor"
|
||||
"github.com/ProtonMail/gopenpgp/constants"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
// RandomToken generates a random token with the key size of the default cipher.
|
||||
// RandomToken generated a random token of the same size of the keysize of the default cipher.
|
||||
func (pgp *GopenPGP) RandomToken() ([]byte, error) {
|
||||
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||
keySize := config.DefaultCipher.KeySize()
|
||||
symKey := make([]byte, keySize)
|
||||
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return symKey, nil
|
||||
return pgp.RandomTokenSize(config.DefaultCipher.KeySize())
|
||||
}
|
||||
|
||||
// RandomTokenWith generates a random token with the given key size.
|
||||
func (pgp *GopenPGP) RandomTokenWith(size int) ([]byte, error) {
|
||||
// RandomTokenSize generates a random token with the specified key size
|
||||
func (pgp *GopenPGP) RandomTokenSize(size int) ([]byte, error) {
|
||||
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||
symKey := make([]byte, size)
|
||||
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
|
||||
|
|
@ -34,12 +26,8 @@ func (pgp *GopenPGP) RandomTokenWith(size int) ([]byte, error) {
|
|||
return symKey, nil
|
||||
}
|
||||
|
||||
// GetSessionFromKeyPacket returns the decrypted session key from a binary
|
||||
// public-key encrypted session key packet.
|
||||
func (pgp *GopenPGP) GetSessionFromKeyPacket(
|
||||
keyPacket []byte, privateKey *KeyRing, passphrase string,
|
||||
) (*SymmetricKey,
|
||||
error) {
|
||||
// DecryptSessionKey returns the decrypted session key from a binary encrypted session key packet.
|
||||
func (keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SymmetricKey, error) {
|
||||
keyReader := bytes.NewReader(keyPacket)
|
||||
packets := packet.NewReader(keyReader)
|
||||
|
||||
|
|
@ -50,15 +38,11 @@ func (pgp *GopenPGP) GetSessionFromKeyPacket(
|
|||
}
|
||||
|
||||
ek := p.(*packet.EncryptedKey)
|
||||
|
||||
rawPwd := []byte(passphrase)
|
||||
var decryptErr error
|
||||
for _, key := range privateKey.entities.DecryptionKeys() {
|
||||
for _, key := range keyRing.entities.DecryptionKeys() {
|
||||
priv := key.PrivateKey
|
||||
if priv.Encrypted {
|
||||
if err := priv.Decrypt(rawPwd); err != nil {
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil {
|
||||
|
|
@ -70,38 +54,22 @@ func (pgp *GopenPGP) GetSessionFromKeyPacket(
|
|||
return nil, decryptErr
|
||||
}
|
||||
|
||||
return getSessionSplit(ek)
|
||||
}
|
||||
|
||||
// KeyPacketWithPublicKey encrypts the session key with the armored publicKey
|
||||
// and returns a binary public-key encrypted session key packet.
|
||||
func (pgp *GopenPGP) KeyPacketWithPublicKey(sessionSplit *SymmetricKey, publicKey string) ([]byte, error) {
|
||||
pubkeyRaw, err := armor.Unarmor(publicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if ek == nil {
|
||||
return nil, errors.New("gopenpgp: unable to decrypt session key")
|
||||
}
|
||||
return pgp.KeyPacketWithPublicKeyBin(sessionSplit, pubkeyRaw)
|
||||
|
||||
return newSymmetricKeyFromEncrypted(ek)
|
||||
}
|
||||
|
||||
// KeyPacketWithPublicKeyBin encrypts the session key with the unarmored
|
||||
// EncryptSessionKey encrypts the session key with the unarmored
|
||||
// publicKey and returns a binary public-key encrypted session key packet.
|
||||
func (pgp *GopenPGP) KeyPacketWithPublicKeyBin(sessionSplit *SymmetricKey, publicKey []byte) ([]byte, error) {
|
||||
publicKeyReader := bytes.NewReader(publicKey)
|
||||
pubKeyEntries, err := openpgp.ReadKeyRing(publicKeyReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (keyRing *KeyRing) EncryptSessionKey(sessionSplit *SymmetricKey) ([]byte, error) {
|
||||
outbuf := &bytes.Buffer{}
|
||||
|
||||
cf := sessionSplit.GetCipherFunc()
|
||||
|
||||
if len(pubKeyEntries) == 0 {
|
||||
return nil, errors.New("cannot set key: key ring is empty")
|
||||
}
|
||||
|
||||
var pub *packet.PublicKey
|
||||
for _, e := range pubKeyEntries {
|
||||
for _, e := range keyRing.GetEntities() {
|
||||
for _, subKey := range e.Subkeys {
|
||||
if !subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications {
|
||||
pub = subKey.PublicKey
|
||||
|
|
@ -125,106 +93,9 @@ func (pgp *GopenPGP) KeyPacketWithPublicKeyBin(sessionSplit *SymmetricKey, publi
|
|||
return nil, errors.New("cannot set key: no public key available")
|
||||
}
|
||||
|
||||
if err = packet.SerializeEncryptedKey(outbuf, pub, cf, sessionSplit.Key, nil); err != nil {
|
||||
if err := packet.SerializeEncryptedKey(outbuf, pub, cf, sessionSplit.Key, nil); err != nil {
|
||||
err = fmt.Errorf("gopenpgp: cannot set key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return outbuf.Bytes(), nil
|
||||
}
|
||||
|
||||
// GetSessionFromSymmetricPacket decrypts the binary symmetrically encrypted
|
||||
// session key packet and returns the session key.
|
||||
func (pgp *GopenPGP) GetSessionFromSymmetricPacket(keyPacket []byte, password string) (*SymmetricKey, error) {
|
||||
keyReader := bytes.NewReader(keyPacket)
|
||||
packets := packet.NewReader(keyReader)
|
||||
|
||||
var symKeys []*packet.SymmetricKeyEncrypted
|
||||
for {
|
||||
|
||||
var p packet.Packet
|
||||
var err error
|
||||
if p, err = packets.Next(); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
switch p := p.(type) {
|
||||
case *packet.SymmetricKeyEncrypted:
|
||||
symKeys = append(symKeys, p)
|
||||
}
|
||||
}
|
||||
|
||||
pwdRaw := []byte(password)
|
||||
// Try the symmetric passphrase first
|
||||
if len(symKeys) != 0 && pwdRaw != nil {
|
||||
for _, s := range symKeys {
|
||||
key, cipherFunc, err := s.Decrypt(pwdRaw)
|
||||
if err == nil {
|
||||
return &SymmetricKey{
|
||||
Key: key,
|
||||
Algo: getAlgo(cipherFunc),
|
||||
}, nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("password incorrect")
|
||||
}
|
||||
|
||||
// SymmetricKeyPacketWithPassword encrypts the session key with the password and
|
||||
// returns a binary symmetrically encrypted session key packet.
|
||||
func (pgp *GopenPGP) SymmetricKeyPacketWithPassword(sessionSplit *SymmetricKey, password string) ([]byte, error) {
|
||||
outbuf := &bytes.Buffer{}
|
||||
|
||||
cf := sessionSplit.GetCipherFunc()
|
||||
|
||||
if len(password) <= 0 {
|
||||
return nil, errors.New("password can't be empty")
|
||||
}
|
||||
|
||||
pwdRaw := []byte(password)
|
||||
|
||||
config := &packet.Config{
|
||||
DefaultCipher: cf,
|
||||
}
|
||||
|
||||
err := packet.SerializeSymmetricKeyEncryptedReuseKey(outbuf, sessionSplit.Key, pwdRaw, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outbuf.Bytes(), nil
|
||||
}
|
||||
|
||||
func getSessionSplit(ek *packet.EncryptedKey) (*SymmetricKey, error) {
|
||||
if ek == nil {
|
||||
return nil, errors.New("can't decrypt key packet")
|
||||
}
|
||||
algo := constants.AES256
|
||||
for k, v := range symKeyAlgos {
|
||||
if v == ek.CipherFunc {
|
||||
algo = k
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ek.Key == nil {
|
||||
return nil, errors.New("can't decrypt key packet key is nil")
|
||||
}
|
||||
|
||||
return &SymmetricKey{
|
||||
Key: ek.Key,
|
||||
Algo: algo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getAlgo(cipher packet.CipherFunction) string {
|
||||
algo := constants.AES256
|
||||
for k, v := range symKeyAlgos {
|
||||
if v == cipher {
|
||||
algo = k
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return algo
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue