passforios-gopenpgp/crypto/session.go

220 lines
5 KiB
Go
Raw Normal View History

package crypto
2018-06-04 16:05:14 -07:00
import (
"bytes"
"errors"
"fmt"
"io"
2018-11-01 17:03:43 +01:00
"github.com/ProtonMail/go-pm-crypto/armor"
2018-06-04 16:05:14 -07:00
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
)
2019-05-13 12:33:01 +00:00
// RandomToken with a default key size
func (pm *PmCrypto) RandomToken() ([]byte, error) {
2018-06-04 16:05:14 -07:00
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
}
2019-05-13 12:33:01 +00:00
// RandomTokenWith a given key size
func (pm *PmCrypto) RandomTokenWith(size int) ([]byte, error) {
2018-06-04 16:05:14 -07:00
config := &packet.Config{DefaultCipher: packet.CipherAES256}
symKey := make([]byte, size)
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
return nil, err
}
return symKey, nil
}
2019-05-13 12:33:01 +00:00
// GetSessionFromKeyPacket gets session key no encoding in and out
func (pm *PmCrypto) GetSessionFromKeyPacket(keyPackage []byte, privateKey *KeyRing, passphrase string) (*SymmetricKey, error) {
2018-06-04 16:05:14 -07:00
keyReader := bytes.NewReader(keyPackage)
packets := packet.NewReader(keyReader)
var p packet.Packet
var err error
if p, err = packets.Next(); err != nil {
return nil, err
}
ek := p.(*packet.EncryptedKey)
rawPwd := []byte(passphrase)
var decryptErr error
for _, key := range privateKey.entities.DecryptionKeys() {
2018-06-04 16:05:14 -07:00
priv := key.PrivateKey
if priv.Encrypted {
if err := priv.Decrypt(rawPwd); err != nil {
continue
}
}
if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil {
break
}
}
if decryptErr != nil {
2019-03-07 14:08:17 +01:00
return nil, decryptErr
2018-06-04 16:05:14 -07:00
}
return getSessionSplit(ek)
}
2019-05-13 12:33:01 +00:00
// KeyPacketWithPublicKey
func (pm *PmCrypto) KeyPacketWithPublicKey(sessionSplit *SymmetricKey, publicKey string) ([]byte, error) {
2018-09-19 11:52:14 +02:00
pubkeyRaw, err := armor.Unarmor(publicKey)
2018-06-04 16:05:14 -07:00
if err != nil {
return nil, err
}
return pm.KeyPacketWithPublicKeyBin(sessionSplit, pubkeyRaw)
2018-06-04 16:05:14 -07:00
}
2019-05-13 12:33:01 +00:00
// KeyPacketWithPublicKeyBin
func (pm *PmCrypto) KeyPacketWithPublicKeyBin(sessionSplit *SymmetricKey, publicKey []byte) ([]byte, error) {
2018-06-04 16:05:14 -07:00
publicKeyReader := bytes.NewReader(publicKey)
pubKeyEntries, err := openpgp.ReadKeyRing(publicKeyReader)
outbuf := &bytes.Buffer{}
cf := sessionSplit.GetCipherFunc()
2018-06-04 16:05:14 -07:00
if len(pubKeyEntries) == 0 {
return nil, errors.New("cannot set key: key ring is empty")
}
var pub *packet.PublicKey
for _, e := range pubKeyEntries {
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 {
return nil, errors.New("cannot set key: no public key available")
}
if err = packet.SerializeEncryptedKey(outbuf, pub, cf, sessionSplit.Key, nil); err != nil {
err = fmt.Errorf("pm-crypto: cannot set key: %v", err)
2018-06-04 16:05:14 -07:00
return nil, errors.New("cannot set key: key ring is empty")
}
return outbuf.Bytes(), nil
}
2019-05-13 12:33:01 +00:00
// GetSessionFromSymmetricPacket
func (pm *PmCrypto) GetSessionFromSymmetricPacket(keyPackage []byte, password string) (*SymmetricKey, error) {
2018-06-04 16:05:14 -07:00
keyReader := bytes.NewReader(keyPackage)
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),
2018-06-04 16:05:14 -07:00
}, nil
}
}
}
return nil, errors.New("password incorrect")
}
2019-05-13 12:33:01 +00:00
// SymmetricKeyPacketWithPassword
func (pm *PmCrypto) SymmetricKeyPacketWithPassword(sessionSplit *SymmetricKey, password string) ([]byte, error) {
2018-06-04 16:05:14 -07:00
outbuf := &bytes.Buffer{}
cf := sessionSplit.GetCipherFunc()
2018-06-04 16:05:14 -07:00
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)
2018-06-04 16:05:14 -07:00
if err != nil {
return nil, err
}
return outbuf.Bytes(), nil
}
func getSessionSplit(ek *packet.EncryptedKey) (*SymmetricKey, error) {
2018-06-04 16:05:14 -07:00
if ek == nil {
return nil, errors.New("can't decrypt key packet")
}
2018-06-04 17:50:26 -07:00
algo := "aes256"
2018-06-04 16:05:14 -07:00
for k, v := range symKeyAlgos {
if v == ek.CipherFunc {
algo = k
break
}
}
2018-06-05 17:56:01 -07:00
if ek.Key == nil {
return nil, errors.New("can't decrypt key packet key is nil")
}
return &SymmetricKey{
Key: ek.Key,
Algo: algo,
2018-06-04 16:05:14 -07:00
}, nil
}
2018-06-04 17:50:26 -07:00
func getAlgo(cipher packet.CipherFunction) string {
algo := "aes256"
2018-06-04 16:05:14 -07:00
for k, v := range symKeyAlgos {
if v == cipher {
algo = k
break
}
}
return algo
2018-09-19 11:52:14 +02:00
}