passforios-gopenpgp/crypto/sessionkey.go

391 lines
11 KiB
Go
Raw Normal View History

package crypto
import (
"bytes"
"encoding/base64"
"fmt"
"io"
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
"time"
"github.com/ProtonMail/gopenpgp/v2/constants"
"github.com/pkg/errors"
"github.com/ProtonMail/go-crypto/openpgp"
2022-02-24 18:57:31 +01:00
pgpErrors "github.com/ProtonMail/go-crypto/openpgp/errors"
"github.com/ProtonMail/go-crypto/openpgp/packet"
)
// 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
}
var symKeyAlgos = map[string]packet.CipherFunction{
constants.ThreeDES: packet.Cipher3DES,
constants.TripleDES: packet.Cipher3DES,
constants.CAST5: packet.CipherCAST5,
constants.AES128: packet.CipherAES128,
constants.AES192: packet.CipherAES192,
constants.AES256: packet.CipherAES256,
}
2022-02-24 18:57:31 +01:00
type checkReader struct {
decrypted io.ReadCloser
body io.Reader
}
func (cr checkReader) Read(buf []byte) (int, error) {
n, sensitiveParsingError := cr.body.Read(buf)
if sensitiveParsingError == io.EOF {
mdcErr := cr.decrypted.Close()
if mdcErr != nil {
return n, mdcErr
}
return n, io.EOF
}
if sensitiveParsingError != nil {
return n, pgpErrors.StructuralError("parsing error")
}
return n, nil
}
// GetCipherFunc returns the cipher function corresponding to the algorithm used
// with this SessionKey.
func (sk *SessionKey) GetCipherFunc() (packet.CipherFunction, error) {
cf, ok := symKeyAlgos[sk.Algo]
if !ok {
return cf, errors.New("gopenpgp: unsupported cipher function: " + sk.Algo)
}
return cf, nil
}
// GetBase64Key returns the session key as base64 encoded string.
func (sk *SessionKey) GetBase64Key() string {
return base64.StdEncoding.EncodeToString(sk.Key)
}
// RandomToken generates a random token with the specified key size.
func RandomToken(size int) ([]byte, error) {
config := &packet.Config{DefaultCipher: packet.CipherAES256}
symKey := make([]byte, size)
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in generating random token")
}
return symKey, nil
}
// GenerateSessionKeyAlgo generates a random key of the correct length for the
// specified algorithm.
func GenerateSessionKeyAlgo(algo string) (sk *SessionKey, err error) {
cf, ok := symKeyAlgos[algo]
if !ok {
return nil, errors.New("gopenpgp: unknown symmetric key generation algorithm")
}
r, err := RandomToken(cf.KeySize())
if err != nil {
return nil, err
}
sk = &SessionKey{
Key: r,
Algo: algo,
}
return sk, nil
}
// GenerateSessionKey generates a random key for the default cipher.
func GenerateSessionKey() (*SessionKey, error) {
return GenerateSessionKeyAlgo(constants.AES256)
}
func NewSessionKeyFromToken(token []byte, algo string) *SessionKey {
return &SessionKey{
Key: clone(token),
Algo: algo,
}
}
func newSessionKeyFromEncrypted(ek *packet.EncryptedKey) (*SessionKey, error) {
var algo string
for k, v := range symKeyAlgos {
if v == ek.CipherFunc {
algo = k
break
}
}
if algo == "" {
return nil, fmt.Errorf("gopenpgp: unsupported cipher function: %v", ek.CipherFunc)
}
sk := &SessionKey{
Key: ek.Key,
Algo: algo,
}
if err := sk.checkSize(); err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to decrypt session key")
}
return sk, nil
}
// Encrypt encrypts a PlainMessage to PGPMessage with a SessionKey.
// * message : The plain data as a PlainMessage.
// * output : The encrypted data as PGPMessage.
func (sk *SessionKey) Encrypt(message *PlainMessage) ([]byte, error) {
dc, err := sk.GetCipherFunc()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt with session key")
}
config := &packet.Config{
Time: getTimeGenerator(),
DefaultCipher: dc,
}
return encryptWithSessionKey(message, sk, nil, config)
}
// EncryptAndSign encrypts a PlainMessage to PGPMessage with a SessionKey and signs it with a Private key.
// * message : The plain data as a PlainMessage.
// * signKeyRing: The KeyRing to sign the message
// * output : The encrypted data as PGPMessage.
func (sk *SessionKey) EncryptAndSign(message *PlainMessage, signKeyRing *KeyRing) ([]byte, error) {
dc, err := sk.GetCipherFunc()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt with session key")
}
config := &packet.Config{
Time: getTimeGenerator(),
DefaultCipher: dc,
}
signEntity, err := signKeyRing.getSigningEntity()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to sign")
}
return encryptWithSessionKey(message, sk, signEntity, config)
}
// EncryptWithCompression encrypts with compression support a PlainMessage to PGPMessage with a SessionKey.
// * message : The plain data as a PlainMessage.
// * output : The encrypted data as PGPMessage.
func (sk *SessionKey) EncryptWithCompression(message *PlainMessage) ([]byte, error) {
dc, err := sk.GetCipherFunc()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt with session key")
}
config := &packet.Config{
Time: getTimeGenerator(),
DefaultCipher: dc,
DefaultCompressionAlgo: constants.DefaultCompression,
CompressionConfig: &packet.CompressionConfig{Level: constants.DefaultCompressionLevel},
}
return encryptWithSessionKey(message, sk, nil, config)
}
func encryptWithSessionKey(message *PlainMessage, sk *SessionKey, signEntity *openpgp.Entity, config *packet.Config) ([]byte, error) {
var encBuf = new(bytes.Buffer)
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
encryptWriter, signWriter, err := encryptStreamWithSessionKey(
message.IsBinary(),
message.Filename,
message.Time,
encBuf,
sk,
signEntity,
config,
)
if err != nil {
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
return nil, err
}
if signEntity != nil {
_, err = signWriter.Write(message.GetBinary())
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in writing signed message")
}
err = signWriter.Close()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in closing signing writer")
}
} else {
_, err = encryptWriter.Write(message.GetBinary())
}
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in writing message")
}
err = encryptWriter.Close()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in closing encryption writer")
}
return encBuf.Bytes(), nil
}
func encryptStreamWithSessionKey(
isBinary bool,
filename string,
modTime uint32,
dataPacketWriter io.Writer,
sk *SessionKey,
signEntity *openpgp.Entity,
config *packet.Config,
) (encryptWriter, signWriter io.WriteCloser, err error) {
encryptWriter, err = packet.SerializeSymmetricallyEncrypted(dataPacketWriter, config.Cipher(), sk.Key, config)
if err != nil {
return nil, nil, errors.Wrap(err, "gopenpgp: unable to encrypt")
}
if algo := config.Compression(); algo != packet.CompressionNone {
encryptWriter, err = packet.SerializeCompressed(encryptWriter, algo, config.CompressionConfig)
if err != nil {
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
return nil, nil, errors.Wrap(err, "gopenpgp: error in compression")
}
}
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
if signEntity != nil {
hints := &openpgp.FileHints{
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
IsBinary: isBinary,
FileName: filename,
ModTime: time.Unix(int64(modTime), 0),
}
signWriter, err = openpgp.Sign(encryptWriter, signEntity, hints, config)
if err != nil {
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
return nil, nil, errors.Wrap(err, "gopenpgp: unable to sign")
}
} else {
encryptWriter, err = packet.SerializeLiteral(
encryptWriter,
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
isBinary,
filename,
modTime,
)
if err != nil {
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
return nil, nil, errors.Wrap(err, "gopenpgp: unable to serialize")
}
}
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
return encryptWriter, signWriter, nil
}
// Decrypt decrypts pgp data packets using directly a session key.
// * encrypted: PGPMessage.
// * output: PlainMessage.
func (sk *SessionKey) Decrypt(dataPacket []byte) (*PlainMessage, error) {
return sk.DecryptAndVerify(dataPacket, nil, 0)
}
// DecryptAndVerify decrypts pgp data packets using directly a session key and verifies embedded signatures.
// * encrypted: PGPMessage.
// * verifyKeyRing: KeyRing with verification public keys
// * verifyTime: when should the signature be valid, as timestamp. If 0 time verification is disabled.
// * output: PlainMessage.
func (sk *SessionKey) DecryptAndVerify(dataPacket []byte, verifyKeyRing *KeyRing, verifyTime int64) (*PlainMessage, error) {
var messageReader = bytes.NewReader(dataPacket)
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
md, err := decryptStreamWithSessionKey(sk, messageReader, verifyKeyRing)
if err != nil {
return nil, err
}
messageBuf := new(bytes.Buffer)
_, err = messageBuf.ReadFrom(md.UnverifiedBody)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: error in reading message body")
}
if verifyKeyRing != nil {
processSignatureExpiration(md, verifyTime)
err = verifyDetailsSignature(md, verifyKeyRing)
}
return &PlainMessage{
Data: messageBuf.Bytes(),
TextType: !md.LiteralData.IsBinary,
Filename: md.LiteralData.FileName,
Time: md.LiteralData.Time,
}, err
}
func decryptStreamWithSessionKey(sk *SessionKey, messageReader io.Reader, verifyKeyRing *KeyRing) (*openpgp.MessageDetails, error) {
var decrypted io.ReadCloser
var keyring openpgp.EntityList
// Read symmetrically encrypted data packet
packets := packet.NewReader(messageReader)
p, err := packets.Next()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to read symmetric packet")
}
// Decrypt data packet
switch p := p.(type) {
case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted:
dc, err := sk.GetCipherFunc()
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to decrypt with session key")
}
encryptedDataPacket, isDataPacket := p.(packet.EncryptedDataPacket)
if !isDataPacket {
return nil, errors.Wrap(err, "gopenpgp: unknown data packet")
}
decrypted, err = encryptedDataPacket.Decrypt(dc, sk.Key)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to decrypt symmetric packet")
}
default:
return nil, errors.New("gopenpgp: invalid packet type")
}
config := &packet.Config{
Time: getTimeGenerator(),
}
// Push decrypted packet as literal packet and use openpgp's reader
if verifyKeyRing != nil {
keyring = verifyKeyRing.entities
} else {
keyring = openpgp.EntityList{}
}
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
md, err := openpgp.ReadMessage(decrypted, keyring, nil, config)
if err != nil {
return nil, errors.Wrap(err, "gopenpgp: unable to decode symmetric packet")
}
2022-02-24 18:57:31 +01:00
md.UnverifiedBody = checkReader{decrypted, md.UnverifiedBody}
Add a streaming api to KeyRing and SessionKey (#131) * barebone streaming functionality * encryption needs to return a writecloser * added eof check * workaround for reader problem with copies * separate mobile wrappers from main api * add a clone in the read result to avoid memory corruption * refactor to reuse code, and fix verification * have to give the verify key at the start of the decryption * enfore readAll before signature verification * streaming api for SessionKey * add split message stream apis * name interface params * fix streaming api so it's supported by go-mobile * hide internal writeCloser * fix nil access * added detached sigs methods * started unit testing * unit testing and fixed a bug where key and data packets where inverted * remove unecessary error wrapping * figured out closing order and error handling * add GC calls to mobile writer and reader * remove debugging values and arrays * writer with builtin sha256 * unit testing the mobile helpers * comments and linting * Typo in error Co-authored-by: wussler <aron@wussler.it> * Add GetKeyPacket doc Co-authored-by: wussler <aron@wussler.it> * Add rfc reference in comments Co-authored-by: wussler <aron@wussler.it> * small improvements * add compatibility tests with normal methods * remove unecessary copies in the tests * update go-crypto to the merged changes commit * update comments of core internal functions * remove unused nolint comment * group message metadata in a struct * fix comments * change default values for metadata * change the mobile reader wrapper to fit the behavior of java * remove gc calls in the wrappers to avoid performance penalties * bring back the former Go2MobileReader to be used for ios * Update crypto/keyring_streaming.go Co-authored-by: wussler <aron@wussler.it> * return an error when verifying an embedded sig with no keyring * Update crypto/sessionkey_streaming.go Co-authored-by: wussler <aron@wussler.it> * linter error * update changelog * update changelog Co-authored-by: wussler <aron@wussler.it>
2021-06-30 16:49:30 +02:00
return md, nil
}
func (sk *SessionKey) checkSize() error {
cf, ok := symKeyAlgos[sk.Algo]
if !ok {
return errors.New("unknown symmetric key algorithm")
}
if cf.KeySize() != len(sk.Key) {
return errors.New("wrong session key size")
}
return nil
}
func getAlgo(cipher packet.CipherFunction) string {
algo := constants.AES256
for k, v := range symKeyAlgos {
if v == cipher {
algo = k
break
}
}
return algo
}