Encrypt session key to multiple keys in keyring. (#59)
`EncryptSessionKey` now creates encrypted key packet for each valid key in keyring. Co-authored-by: Aron Wussler <aron@wussler.it>
This commit is contained in:
parent
a232124b70
commit
b38f993c25
5 changed files with 33 additions and 11 deletions
|
|
@ -26,3 +26,4 @@ linters:
|
||||||
- lll # Reports long lines [fast: true, auto-fix: false]
|
- lll # Reports long lines [fast: true, auto-fix: false]
|
||||||
- testpackage # Makes you use a separate _test package [fast: true, auto-fix: false]
|
- testpackage # Makes you use a separate _test package [fast: true, auto-fix: false]
|
||||||
- wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
|
- wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
|
||||||
|
- gofumpt # Enforce a stricter format than gofmt
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Improved key and message armoring testing
|
- Improved key and message armoring testing
|
||||||
|
- `EncryptSessionKey` now creates encrypted key packets for each valid encryption key in the provided keyring.
|
||||||
|
Returns a byte slice with all the concatenated key packets.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Public key armoring headers
|
- Public key armoring headers
|
||||||
|
|
|
||||||
|
|
@ -331,13 +331,13 @@ A session key can be generated, encrypted to a Asymmetric/Symmetric key packet a
|
||||||
|
|
||||||
sessionKey, err := crypto.GenerateSessionKey()
|
sessionKey, err := crypto.GenerateSessionKey()
|
||||||
|
|
||||||
keyPacket, err := publicKeyRing.EncryptSessionKey(sessionKey)
|
keyPacket, err := publicKeyRing.EncryptSessionKey(sessionKey) // Will encrypt to all the keys in the keyring
|
||||||
keyPacketSymm, err := crypto.EncryptSessionKeyWithPassword(sessionKey, password)
|
keyPacketSymm, err := crypto.EncryptSessionKeyWithPassword(sessionKey, password)
|
||||||
```
|
```
|
||||||
`KeyPacket` is a `[]byte` containing the session key encrypted with the private key or password.
|
`KeyPacket` is a `[]byte` containing the session key encrypted with the private key or password.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
decodedKeyPacket, err := privateKeyRing.DecryptSessionKey(keyPacket)
|
decodedKeyPacket, err := privateKeyRing.DecryptSessionKey(keyPacket) // Will decode with the first valid key found
|
||||||
decodedSymmKeyPacket, err := crypto.DecryptSessionKeyWithPassword(keyPacketSymm, password)
|
decodedSymmKeyPacket, err := crypto.DecryptSessionKeyWithPassword(keyPacketSymm, password)
|
||||||
```
|
```
|
||||||
`decodedKeyPacket` and `decodedSymmKeyPacket` are objects of type `*SymmetricKey` that can
|
`decodedKeyPacket` and `decodedSymmKeyPacket` are objects of type `*SymmetricKey` that can
|
||||||
|
|
|
||||||
|
|
@ -48,26 +48,26 @@ func (keyRing *KeyRing) DecryptSessionKey(keyPacket []byte) (*SessionKey, error)
|
||||||
// publicKey and returns a binary public-key encrypted session key packet.
|
// publicKey and returns a binary public-key encrypted session key packet.
|
||||||
func (keyRing *KeyRing) EncryptSessionKey(sk *SessionKey) ([]byte, error) {
|
func (keyRing *KeyRing) EncryptSessionKey(sk *SessionKey) ([]byte, error) {
|
||||||
outbuf := &bytes.Buffer{}
|
outbuf := &bytes.Buffer{}
|
||||||
|
|
||||||
cf, err := sk.GetCipherFunc()
|
cf, err := sk.GetCipherFunc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key")
|
return nil, errors.Wrap(err, "gopenpgp: unable to encrypt session key")
|
||||||
}
|
}
|
||||||
|
|
||||||
var pub *packet.PublicKey
|
var pubKeys []*packet.PublicKey
|
||||||
for _, e := range keyRing.entities {
|
for _, e := range keyRing.entities {
|
||||||
if encryptionKey, ok := e.EncryptionKey(getNow()); ok {
|
if encryptionKey, ok := e.EncryptionKey(getNow()); ok {
|
||||||
pub = encryptionKey.PublicKey
|
pubKeys = append(pubKeys, encryptionKey.PublicKey)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pub == nil {
|
if len(pubKeys) == 0 {
|
||||||
return nil, errors.New("cannot set key: no public key available")
|
return nil, errors.New("cannot set key: no public key available")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, pub := range pubKeys {
|
||||||
if err := packet.SerializeEncryptedKey(outbuf, pub, cf, sk.Key, nil); err != nil {
|
if err := packet.SerializeEncryptedKey(outbuf, pub, cf, sk.Key, nil); err != nil {
|
||||||
err = fmt.Errorf("gopenpgp: cannot set key: %v", err)
|
err = fmt.Errorf("gopenpgp: cannot set key: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return outbuf.Bytes(), nil
|
return outbuf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,21 @@ func TestAsymmetricKeyPacket(t *testing.T) {
|
||||||
assert.Exactly(t, testSessionKey, outputSymmetricKey)
|
assert.Exactly(t, testSessionKey, outputSymmetricKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMultipleAsymmetricKeyPacket(t *testing.T) {
|
||||||
|
keyPacket, err := keyRingTestMultiple.EncryptSessionKey(testSessionKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error while generating key packet, got:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Password defined in keyring_test
|
||||||
|
outputSymmetricKey, err := keyRingTestMultiple.DecryptSessionKey(keyPacket)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error while decrypting key packet, got:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Exactly(t, testSessionKey, outputSymmetricKey)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSymmetricKeyPacket(t *testing.T) {
|
func TestSymmetricKeyPacket(t *testing.T) {
|
||||||
password := []byte("I like encryption")
|
password := []byte("I like encryption")
|
||||||
|
|
||||||
|
|
@ -90,7 +105,8 @@ func TestDataPacketEncryption(t *testing.T) {
|
||||||
assert.Exactly(t, message.GetString(), decrypted.GetString())
|
assert.Exactly(t, message.GetString(), decrypted.GetString())
|
||||||
|
|
||||||
// Encrypt session key
|
// Encrypt session key
|
||||||
keyPacket, err := keyRingTestPublic.EncryptSessionKey(testSessionKey)
|
assert.Exactly(t, 3, len(keyRingTestMultiple.entities))
|
||||||
|
keyPacket, err := keyRingTestMultiple.EncryptSessionKey(testSessionKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unable to encrypt key packet, got:", err)
|
t.Fatal("Unable to encrypt key packet, got:", err)
|
||||||
}
|
}
|
||||||
|
|
@ -108,6 +124,9 @@ func TestDataPacketEncryption(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unable to unarmor pgp message, got:", err)
|
t.Fatal("Unable to unarmor pgp message, got:", err)
|
||||||
}
|
}
|
||||||
|
ids, ok := pgpMessage.getEncryptionKeyIDs()
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Exactly(t, 3, len(ids))
|
||||||
|
|
||||||
// Test if final decryption succeeds
|
// Test if final decryption succeeds
|
||||||
finalMessage, err := keyRingTestPrivate.Decrypt(pgpMessage, nil, 0)
|
finalMessage, err := keyRingTestPrivate.Decrypt(pgpMessage, nil, 0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue