passforios-gopenpgp/key.go

335 lines
8.3 KiB
Go
Raw Normal View History

2018-06-04 16:05:14 -07:00
package pm
import (
"bytes"
2018-06-06 14:05:57 -07:00
"crypto"
2018-06-04 16:05:14 -07:00
"encoding/hex"
"errors"
"fmt"
"strings"
"time"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
"math/big"
2018-06-04 16:05:14 -07:00
)
//EncryptedSplit when encrypt attachemt
type EncryptedSplit struct {
DataPacket []byte
KeyPacket []byte
Algo string
}
//SessionSplit splited session
type SessionSplit struct {
Session []byte
Algo string
}
//EncryptedSigned encrypt_sign_package
type EncryptedSigned struct {
Encrypted string
Signature string
}
const (
ok = 0
notSigned = 1
noVerifier = 2
failed = 3
)
//DecryptSignedVerify decrypt_sign_verify
type DecryptSignedVerify struct {
//clear text
Plaintext string
//bitmask verify status : 0
Verify int
//error message if verify failed
Message string
}
//CheckPassphrase check is private key passphrase ok
func CheckPassphrase(privateKey string, passphrase string) bool {
privKeyReader := strings.NewReader(privateKey)
entries, err := openpgp.ReadArmoredKeyRing(privKeyReader)
if err != nil {
fmt.Println(err)
return false
}
var keys []*packet.PrivateKey
for _, e := range entries {
keys = append(keys, e.PrivateKey)
}
var decryptError error
var n int
for _, key := range keys {
if !key.Encrypted {
continue // Key already decrypted
}
if decryptError = key.Decrypt([]byte(passphrase)); decryptError == nil {
n++
}
}
if n == 0 {
return false
}
return true
}
//IsKeyExpiredBin ...
func (o *OpenPGP) IsKeyExpiredBin(publicKey []byte) (bool, error) {
now := o.getNow()
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() &&
!subkey.Sig.KeyExpired(now) &&
(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() &&
!i.SelfSignature.KeyExpired(now) {
return false, nil
}
}
}
return true, errors.New("keys expired")
}
//IsKeyExpired ....
// will user the cached time to check
func (o *OpenPGP) IsKeyExpired(publicKey string) (bool, error) {
rawPubKey, err := UnArmor(publicKey)
if err != nil {
return false, err
}
return o.IsKeyExpiredBin(rawPubKey)
}
func (o *OpenPGP) generateKey(userName string, domain string, passphrase string, keyType string, bits int,
prime1 []byte, prime2 []byte, prime3 []byte, prime4 []byte) (string, error) {
2018-06-04 16:05:14 -07:00
if len(userName) <= 0 {
return "", errors.New("Invalid user name format")
}
var email = userName
if len(domain) > 0 {
email = email + "@" + domain
2018-06-04 16:05:14 -07:00
}
2018-06-04 16:05:14 -07:00
comments := ""
2018-06-06 14:05:57 -07:00
cfg := &packet.Config{
Algorithm: packet.PubKeyAlgoRSA,
2018-06-06 14:05:57 -07:00
RSABits: bits,
Time: o.getTimeGenerator(),
2018-06-06 14:05:57 -07:00
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[:]
}
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
}
2018-06-04 16:05:14 -07:00
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()
2018-06-04 17:50:26 -07:00
return ArmorWithType(serialized, pgpPrivateBlockType)
2018-06-04 16:05:14 -07:00
}
func (o *OpenPGP) GenerateRSAKeyWithPrimes(userName string, domain string, passphrase string, bits int,
primeone []byte, primetwo []byte, primethree []byte, primefour []byte) (string, error) {
return o.generateKey(userName, domain, passphrase, "rsa", bits, primeone, primetwo, primethree, primefour)
}
// GenerateKey ...
// disabled now, will enable later
// #generat new key with email address. Fix the UserID issue in protonmail system. on Feb 28, 17
// #static generate_key_with_email(email : string, passphrase : string, bits : i32) : open_pgp_key;
// # generate new key
// #static generate_new_key(user_id : string, email : string, passphrase : string, bits : i32) : open_pgp_key;
func (o *OpenPGP) GenerateKey(userName string, domain string, passphrase string, keyType string, bits int) (string, error) {
return o.generateKey(userName, domain, passphrase, keyType, bits, nil, nil, nil, nil)
}
2018-06-04 16:05:14 -07:00
// UpdatePrivateKeyPassphrase ...
func (o *OpenPGP) 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()
2018-06-04 17:50:26 -07:00
return ArmorWithType(serialized, pgpPrivateBlockType)
2018-06-04 16:05:14 -07:00
}
// PublicKey get a public key from a private key
func PublicKey(privateKey string) (string, error) {
privKeyReader := strings.NewReader(privateKey)
entries, err := openpgp.ReadArmoredKeyRing(privKeyReader)
if err != nil {
return "", err
}
var outBuf bytes.Buffer
for _, e := range entries {
e.Serialize(&outBuf)
}
2018-06-04 17:50:26 -07:00
outString, err := ArmorWithType(outBuf.Bytes(), pgpPublicBlockType)
2018-06-04 16:05:14 -07:00
if err != nil {
return "", nil
}
return outString, nil
}
// PublicKeyBinOut get a public key from a private key
func PublicKeyBinOut(privateKey string) ([]byte, error) {
privKeyReader := strings.NewReader(privateKey)
entries, err := openpgp.ReadArmoredKeyRing(privKeyReader)
if err != nil {
return nil, err
}
var outBuf bytes.Buffer
for _, e := range entries {
e.Serialize(&outBuf)
}
return outBuf.Bytes(), nil
}
// CheckKey print out the key and subkey fingerprint
func CheckKey(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 {
println("SubKey:" + hex.EncodeToString(subKey.PublicKey.Fingerprint[:]))
}
}
println("PrimaryKey:" + hex.EncodeToString(e.PrimaryKey.Fingerprint[:]))
}
return "", nil
}