* Fix TestMultipleKeyMessageEncryption * Fix TestMultipleKeyMessageEncryption - simplify code * Add diffs to changelog * Simplify test code further
21 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Fixed
- Fixed test
TestMultipleKeyMessageEncryption
[2.0.0] - 2020-01-06
Since the open-sourcing of the library in May the API has been updated, listening to internal and external feedback, in order to have a flexible library, that can be used in a simple settings, with batteries included, or by more advanced users that might want to interact directly with the inner structure of the PGP messages and keys.
It allows direct interaction with keys and keyrings, passphrases, as well as session keys. It is designed with gomobile users in mind, so that they can use the full power of the library, without having to rely on a further wrapper.
This version comes with some design improvements, in particular the introduction of keys
Security
- Dropped the use of strings for secrets
- New key checking functions
- Clear memory after use, in an attempt to reduce leftover secrets in RAM.
- Improved testing, in this and the underlying crypto library
Fixed
KeyRings can now only be unencrypted, removing the problem of mixed encrypted/decrypted keyring, that caused keys not to be recognised.- Explicit key decryption and encryption.
- Underlying crypto library update.
- Underlying MIME library update.
- Fixed ECC critical bugs.
- Removed gopenpgp/pmcrypto object as it could create multiple globals. Methods are now static on the crypto object.
Removed
SignaturestructSignature#KeyRingfunctionSignature#IsByfunctionpmKeyObjectstructencodedLengthfunction, internal and and unusedEncryptCoreis now internal.RandomTokenWith,RandomTokennow takes a size- In the
KeyRingstruct:KeyRing#GetEntities, entities are handled by the libKeyRing#GetSigningEntity, has been made internalKeyRing#Unlock, the unlocking functionalities are on now on the key objectBuildKeyRingNoError,BuildKeyRingArmored,BuildKeyRinguseNewKeyorNewKeyFromArmoredand handle errors then join them into KeyRings.ReadKeyRing,ReadArmoredKeyRing, useNewKeyFromArmoredReaderorNewKeyFromReader.UnmarshalJSON, the interface to unmarshal JSON is not relevant to this library.
Added
Keystruct, to store, import (unserialize) and export (serialize) keys.
// Key contains a single private or public key
type Key struct {
// PGP entities in this keyring.
entity *openpgp.Entity
}
// With the functions
NewKeyFromArmoredReader(r io.Reader) (key *Key, err error)
NewKeyFromReader(r io.Reader) (key *Key, err error)
NewKey(binKeys []byte) (key *Key, err error)
NewKeyFromArmored(armored string) (key *Key, err error)
GenerateKey(name, email string, keyType string, bits int) (*Key, error)
GenerateRSAKeyWithPrimes(name, email string, bits int, primeone, primetwo, primethree, primefour []byte) (*Key, error)
(key *Key) Clone() (*Key, error)
(key *Key) Lock(passphrase []byte) (*Key, error)
(key *Key) Unlock(passphrase []byte) (*Key, error)
(key *Key) Serialize() ([]byte, error)
(key *Key) Armor() (string, error)
(key *Key) GetArmoredPublicKey() (s string, err error)
(key *Key) GetPublicKey() (b []byte, err error)
(key *Key) IsExpired() bool
(key *Key) IsPrivate() bool
(key *Key) IsLocked() (bool, error)
(key *Key) IsUnlocked() (bool, error)
(key *Key) Check() (bool, error)
(key *Key) PrintFingerprints()
(key *Key) GetHexKeyID() string
(key *Key) GetKeyID() uint64
(key *Key) GetFingerprint() string
(key *Key) ClearPrivateParams() (ok bool)
- In the
KeyRingobject:
NewKeyRing(key *Key) (*KeyRing, error)
(keyRing *KeyRing) AddKey(key *Key) error
(keyRing *KeyRing) GetKeys() []*Key
(keyRing *KeyRing) GetKey(n int) (*Key, error)
(keyRing *KeyRing) CountEntities() int
(keyRing *KeyRing) CountDecryptionEntities() int
(keyRing *KeyRing) GetIdentities() []*Identity
(keyRing *KeyRing) FirstKey() (*KeyRing, error)
(keyRing *KeyRing) Clone() (*KeyRing, error)
(keyRing *KeyRing) ClearPrivateParams()
PlainMessagestruct, to store un-encrypted messages
// PlainMessage stores a plain text / unencrypted message.
type PlainMessage struct {
// The content of the message
Data []byte
// if the content is text or binary
TextType bool
}
// With the functions
NewPlainMessage(data []byte) *PlainMessage
NewPlainMessageFromString(text string) *PlainMessage
(msg *PlainMessage) GetBinary()
(msg *PlainMessage) GetString()
(msg *PlainMessage) GetBase64()
(msg *PlainMessage) NewReader()
(msg *PlainMessage) IsText()
(msg *PlainMessage) IsBinary()
PGPMessagestruct, to store encrypted PGP messages
// PGPMessage stores a PGP-encrypted message.
type PGPMessage struct {
// The content of the message
Data []byte
}
// With the functions
NewPGPMessage(data []byte) *PGPMessage
NewPGPMessageFromArmored(armored string) (*PGPMessage, error)
(msg *PGPMessage) GetBinary() []byte
(msg *PGPMessage) NewReader() io.Reader
(msg *PGPMessage) GetArmored() (string, error)
(msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error)
PGPSignaturestruct, to store detached PGP signatures
// PGPSignature stores a PGP-encoded detached signature.
type PGPSignature struct {
// The content of the message
Data []byte
}
// With the functions
NewPGPSignature(data []byte) *PGPSignature
NewPGPSignatureFromArmored(armored string) (*PGPSignature, error)
(msg *PGPSignature) GetBinary() []byte
(msg *PGPSignature) GetArmored() (string, error)
SignatureVerificationErrorstruct, to separate signature verification errors from decryption errors
// SignatureVerificationError is returned from Decrypt and VerifyDetached functions when signature verification fails
type SignatureVerificationError struct {
Status int
Message string
}
Changed
-
IsKeyExpiredBinhas been renamed toIsKeyExpired -
IsKeyExpiredhas been renamed toIsArmoredKeyExpired -
CheckKeyhas been renamed toPrintFingerprints -
KeyRing#ArmoredPublicKeyStringhas been renamed toKeyRing#GetArmoredPublicKey -
KeyRing#KeyIdshas been renamed toKeyRing#GetKeyIDs -
GetTimeUnixwas renamed toGetUnixTime -
EncryptedSplithas been changed toPGPSplitMessage
models.EncryptedSplit struct {
DataPacket []byte
KeyPacket []byte
Algo string
}
// Is now
crypto.PGPSplitMessage struct {
DataPacket []byte
KeyPacket []byte
}
// With the functions
NewPGPSplitMessage(keyPacket []byte, dataPacket []byte) *PGPSplitMessage
NewPGPSplitMessageFromArmored(encrypted string) (*PGPSplitMessage, error)
(msg *PGPSplitMessage) GetBinaryDataPacket() []byte
(msg *PGPSplitMessage) GetBinaryKeyPacket() []byte
(msg *PGPSplitMessage) GetBinary() []byte
(msg *PGPSplitMessage) GetArmored() (string, error)
DecryptSignedVerifyhas been changed toExplicitVerifyMessage
models.DecryptSignedVerify struct {
//clear text
Plaintext string
//bitmask verify status : 0
Verify int
//error message if verify failed
Message string
}
// Is now
// ExplicitVerifyMessage contains explicitely the signature verification error, for gomobile users
type ExplicitVerifyMessage struct {
Message *crypto.PlainMessage
SignatureVerificationError *crypto.SignatureVerificationError
}
// With the new helper
DecryptExplicitVerify (pgpMessage *crypto.PGPMessage, privateKeyRing, publicKeyRing *crypto.KeyRing, verifyTime int64) (*ExplicitVerifyMessage, error)
SignedStringhas been changed toClearTextMessage
// SignedString wraps string with Signature
type SignedString struct {
String string
Signed *Signature
}
// Is now
// ClearTextMessage, split signed clear text message container
type ClearTextMessage struct {
Data []byte
Signature []byte
}
// With the functions
NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage
NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error)
(msg *ClearTextMessage) GetBinary() []byte
(msg *ClearTextMessage) GetString() string
(msg *ClearTextMessage) GetBinarySignature() []byte
(msg *ClearTextMessage) GetArmored() (string, error)
SymmetricKeyhas been renamed toSessionKey
// SessionKey stores a decrypted session key.
type SessionKey struct {
// The decrypted binary session key.
Key []byte
// The symmetric encryption algorithm used with this key.
Algo string
}
// With the functions
NewSessionKeyFromToken(token []byte, algo string) *SessionKey
GenerateSessionKey() (*SessionKey, error)
GenerateSessionKeyAlgo(algo string) (sk *SessionKey, err error)
(sk *SessionKey) GetCipherFunc() packet.CipherFunction
(sk *SessionKey) GetBase64Key() string
(sk *SessionKey) Encrypt(message *PlainMessage) ([]byte, error)
(sk *SessionKey) Decrypt(dataPacket []byte) (*PlainMessage, error)
(sk *SessionKey) Clear() (ok bool)
ReadClearSignedMessagemoved to crypto package and renamed toNewClearTextMessageFromArmored. Changed to returnClearTextMessage.
ReadClearSignedMessage(signedMessage string) (string, error)
// Is now
NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error)
// In addition, were added:
NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage
(msg *ClearTextMessage) GetBinary() []byte
(msg *ClearTextMessage) GetString() string
(msg *ClearTextMessage) GetBinarySignature() []byte
(msg *ClearTextMessage) GetArmored() (string, error)
// As helpers were added:
SignCleartextMessageArmored(privateKey string, passphrase []byte, text string) (string, error)
VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64) (string, error)
SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error)
VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime int64) (string, error)
EncryptAttachment's parameters are changed to messages.
(pm *PmCrypto) EncryptAttachment(plainData []byte, fileName string, publicKey *KeyRing) (*models.EncryptedSplit, error)
// Is now
(keyRing *KeyRing) EncryptAttachment(message *PlainMessage, fileName string) (*PGPSplitMessage, error)
// As a helper was added:
EncryptSignAttachment(publicKey, privateKey string, passphrase []byte, fileName string, plainData []byte) (keyPacket, dataPacket, signature []byte, err error)
DecryptAttachmenthas been moved to KeyRing struct (likeEncryptAttachment)
(pm *PmCrypto) DecryptAttachment(keyPacket []byte, dataPacket []byte, kr *KeyRing, passphrase string) ([]byte, error)
// Is now
(keyRing *KeyRing) DecryptAttachment(message *PGPSplitMessage) (*PlainMessage, error)
// As a helper was added:
DecryptVerifyAttachment(publicKey, privateKey string, passphrase, keyPacket, dataPacket []byte, armoredSignature string) (plainData []byte, err error)
EncryptAttachmentLowMemorywas renamed toNewLowMemoryAttachmentProcessor.
(pm *PmCrypto) EncryptAttachmentLowMemory(estimatedSize int, fileName string, publicKey *KeyRing) (*AttachmentProcessor, error)
// Is now
(keyRing *KeyRing) NewLowMemoryAttachmentProcessor(estimatedSize int, fileName string) (*AttachmentProcessor, error)
SplitArmorwas renamed toNewPGPSplitMessageFromArmoredand the model changed.
SplitArmor(encrypted string) (*models.EncryptedSplit, error)
// Is now
NewPGPSplitMessageFromArmored(encrypted string) (*PGPSplitMessage, error)
DecryptAttKeywas renamed toDecryptSessionKeyand the parameter keypacket changed to[]byteas it's binary, not armored.
DecryptAttKey(kr *KeyRing, keyPacket string) (key *SymmetricKey, err error):
// Is now
(keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error)
SetKeyhas been renamed toEncryptSessionKey, and the keypacket return value changed to[]byte.
SetKey(kr *KeyRing, symKey *SymmetricKey) (packets string, err error):
// Is now
(keyRing *KeyRing) EncryptSessionKey(sessionSplit *SessionKey) ([]byte, error)
SeparateKeyAndDatahas been split in two different function, as it did not only separate the data, but when provided a KeyRing decrypted the session key too.
SeparateKeyAndData(kr *KeyRing, r io.Reader, estimatedLength int, garbageCollector int) (outSplit *models.EncryptedSplit, err error):
// Is now the conjunction of the following function:
// To separate key and data
(msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error)
// To decrypt the SessionKey
(keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error)
EncryptSymmetrichas been changed, now the procedure is split in two parts:EncryptandSeparateKeyAndData
(kr *KeyRing) EncryptSymmetric(textToEncrypt string, canonicalizeText bool) (outSplit *models.EncryptedSplit, err error):
// Is now the conjunction of the following function:
// To encrypt
(keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error)
// To separate key and data
(msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error)
GenerateKey's signature has been altered:- It now returns a
Keystruct userNameanddomainare now joined inemail, thenameparameter was added (To emulate the old behaviourname = email = userName + "@" + domain).
- It now returns a
(pm *PmCrypto) GenerateKey(userName, domain, passphrase, keyType string, bits int) (string, error) :
// Is now
GenerateKey(name, email string, keyType string, bits int) (*Key, error)
// As a helper was added:
GenerateKey(name, email string, passphrase []byte, keyType string, bits int) (string, error)
GenerateRSAKeyWithPrimes's signature has been altered:- It now returns a
Keystruct userNameanddomainare now joined inemail, thenameparameter was added (To emulate the old behaviourname = email = userName + "@" + domain).
- It now returns a
(pm *PmCrypto) GenerateRSAKeyWithPrimes(userName, domain, passphrase, keyType string, bits int, prime1, prime2, prime3, prime4 []byte) (string, error):
GenerateRSAKeyWithPrimes(name, email string, bits int, primeone, primetwo, primethree, primefour []byte,) (*Key, error)
Encrypt,EncryptArmored,EncryptString,EncryptMessagefunctions have been changed to return and accept messages.
(kr *KeyRing) Encrypt(w io.Writer, sign *KeyRing, filename string, canonicalizeText bool) (io.WriteCloser, error)
// Is now
(keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error)
// As a helpers were added:
EncryptMessageArmored(publicKey, plaintext string) (ciphertext string, err error)
EncryptSignMessageArmored(publicKey, privateKey string, passphrase []byte, plaintext string) (ciphertext string, err error) {
Decrypt,DecryptArmored,DecryptString,DecryptMessage,DecryptMessageVerify, andDecryptMessageStringKeyfunctions have been changed to return and accept messages (Same as Encrypt*). If signature verification fails they will return a SignatureVerificationError.
(kr *KeyRing) DecryptString(encrypted string) (SignedString, error)
// Is now
(keyRing *KeyRing) Decrypt(message *PGPMessage, verifyKey *KeyRing, verifyTime int64) (*PlainMessage, error)
// As a helpers were added:
DecryptMessageArmored(privateKey string, passphrase []byte, ciphertext string) (plaintext string, err error)
DecryptVerifyMessageArmored(publicKey, privateKey string, passphrase []byte, ciphertext string) (plaintext string, err error)
DecryptExplicitVerify(pgpMessage *crypto.PGPMessage, privateKeyRing, publicKeyRing *crypto.KeyRing, verifyTime int64) (*ExplicitVerifyMessage, error) {
DecryptStringIfNeededhas been replaced withIsPGPMessage+Decrypt*.
(kr *KeyRing) DecryptStringIfNeeded(data string) (decrypted string, err error)
// Is now the conjunction of the following function:
// To check if the data is a PGP message
IsPGPMessage(data string) bool
// To decrypt
(keyRing *KeyRing) Decrypt(message *PGPMessage, verifyKey *KeyRing, verifyTime int64) (*PlainMessage, error)
SignStringandDetachedSignhave been replaced by signing methods.
(kr *KeyRing) SignString(message string, canonicalizeText bool) (signed string, err error)
(kr *KeyRing) DetachedSign(w io.Writer, toSign io.Reader, canonicalizeText bool, armored bool)
// Are now
(keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, error)
VerifyStringhas been altered in the same way as as signing. Returns SignatureVerificationError if the verification fails.
(kr *KeyRing) VerifyString(message, signature string, sign *KeyRing) (err error)
// Is now
(keyRing *KeyRing) VerifyDetached(message *PlainMessage, signature *PGPSignature, verifyTime int64) error
EncryptMessageWithPassworduses AES-256 instead of AES-128, and has a new signature.
(pm *PmCrypto) EncryptMessageWithPassword(plaintext string, password string) (string, error)
// Is now
EncryptMessageWithPassword(message *PlainMessage, password []byte) (*PGPMessage, error)
// As a helper was added:
EncryptMessageWithPassword(password []byte, plaintext string) (ciphertext string, err error)
DecryptMessageWithPasswordaccepts all symmetric algorithms known to the lib, and has a new signature
(pm *PmCrypto) DecryptMessageWithPassword(encrypted string, password string) (string, error)
// Is now
DecryptMessageWithPassword(message *PGPMessage, password []byte) (*PlainMessage, error)
// As a helper was added:
DecryptMessageWithPassword(password []byte, ciphertext string) (plaintext string, err error)
DecryptMIMEMessagewas moved toKeyRing, and the parameters transformed to messages
(pm *PmCrypto) DecryptMIMEMessage(encryptedText string, verifierKey *KeyRing, privateKeyRing *KeyRing, passphrase string, callbacks MIMECallbacks, verifyTime int64):
// Is now
(keyRing *KeyRing) DecryptMIMEMessage(message *PGPMessage, verifyKey *KeyRing, callbacks MIMECallbacks, verifyTime int64)
RandomTokennow takes a size
(pm *PmCrypto) RandomToken() ([]byte, error)
// Is now
RandomToken(size int) ([]byte, error)
GetSessionFromKeyPacketwas changed toDecryptSessionKey.
(pm *PmCrypto) GetSessionFromKeyPacket(keyPackage []byte, privateKey *KeyRing, passphrase string) (*SymmetricKey, error)
// Is now
(keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error)
KeyPacketWithPublicKeyandKeyPacketWithPublicKeyBinhave been merged toEncryptSessionKey.
(pm *PmCrypto) KeyPacketWithPublicKey(sessionSplit *SymmetricKey, publicKey string) ([]byte, error)
(pm *PmCrypto) KeyPacketWithPublicKeyBin(sessionSplit *SymmetricKey, publicKey []byte) ([]byte, error)
(keyRing *KeyRing) EncryptSessionKey(sk *SessionKey) ([]byte, error)
GetSessionFromSymmetricPacketwas renamed toDecryptSessionKeyWithPassword.
(pm *PmCrypto) GetSessionFromSymmetricPacket(keyPackage []byte, password string) (*SymmetricKey, error)
// Is now
DecryptSessionKeyWithPassword(keyPacket, password []byte) (*SessionKey, error)
SymmetricKeyPacketWithPasswordhas been renamed toEncryptSessionKeyWithPassword
(pm *PmCrypto) SymmetricKeyPacketWithPassword(sessionSplit *SymmetricKey, password string) ([]byte, error):
EncryptSessionKeyWithPassword(sk *SessionKey, password []byte]) ([]byte, error)
SignTextDetachedandSignBinDetachedhave been changed toSignDetached
(pm *PmCrypto) SignTextDetached(plaintext string, privateKey *KeyRing, passphrase string, trim bool) (string, error)
(pm *PmCrypto) SignBinDetached(plainData []byte, privateKey *KeyRing, passphrase string) (string, error)
// Are now
(keyRing *KeyRing) SignDetached(message *PlainMessage) (*PGPSignature, error)
// As helpers were added:
SignCleartextMessage(keyRing *crypto.KeyRing, text string) (string, error)
SignCleartextMessageArmored(privateKey string, passphrase []byte, text string) (string, error)
VerifyTextSignDetachedBinKeyandVerifyBinSignDetachedBinKeyhave been changed toVerify.
(pm *PmCrypto) VerifyTextSignDetachedBinKey(signature string, plaintext string, publicKey *KeyRing, verifyTime int64) (bool, error):
(pm *PmCrypto) VerifyBinSignDetachedBinKey(signature string, plainData []byte, publicKey *KeyRing, verifyTime int64) (bool, error)
// Are now
(keyRing *KeyRing) VerifyDetached(message *PlainMessage, signature *PGPSignature, verifyTime int64) error
// As helpers were added:
VerifyCleartextMessage(keyRing *crypto.KeyRing, armored string, verifyTime int64) (string, error)
VerifyCleartextMessageArmored(publicKey, armored string, verifyTime int64) (string, error)
[1.0.0] - 2019-05-15
Initial release, opensourcing of the internal library PMCrypto, and subsequent renaming to gopenpgp