new helpers for drive decryption (#73)
* new helpers for drive decryption * modular helper functions and reciprocals * removed duplicates helper functions * added mobile wrapper * unit tests for new helpers Co-authored-by: wussler <aron@wussler.it>
This commit is contained in:
parent
af371097e0
commit
39c2fa863e
3 changed files with 231 additions and 38 deletions
190
helper/helper.go
190
helper/helper.go
|
|
@ -168,49 +168,18 @@ func DecryptVerifyAttachment(
|
||||||
passphrase, keyPacket, dataPacket []byte,
|
passphrase, keyPacket, dataPacket []byte,
|
||||||
armoredSignature string,
|
armoredSignature string,
|
||||||
) (plainData []byte, err error) {
|
) (plainData []byte, err error) {
|
||||||
var publicKeyObj, privateKeyObj, unlockedKeyObj *crypto.Key
|
// We decrypt the attachment
|
||||||
var publicKeyRing, privateKeyRing *crypto.KeyRing
|
message, err := decryptAttachment(privateKey, passphrase, keyPacket, dataPacket)
|
||||||
var detachedSignature *crypto.PGPSignature
|
if err != nil {
|
||||||
var message *crypto.PlainMessage
|
|
||||||
|
|
||||||
var packets = crypto.NewPGPSplitMessage(keyPacket, dataPacket)
|
|
||||||
|
|
||||||
if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if publicKeyObj.IsPrivate() {
|
|
||||||
publicKeyObj, err = publicKeyObj.ToPublic()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil {
|
// We verify the signature
|
||||||
|
var check bool
|
||||||
|
if check, err = verifyDetachedArmored(publicKey, message, armoredSignature); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if !check {
|
||||||
if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer unlockedKeyObj.ClearPrivateParams()
|
|
||||||
|
|
||||||
if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if detachedSignature, err = crypto.NewPGPSignatureFromArmored(armoredSignature); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if message, err = privateKeyRing.DecryptAttachment(packets); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if publicKeyRing.VerifyDetached(message, detachedSignature, crypto.GetUnixTime()) != nil {
|
|
||||||
return nil, errors.New("gopenpgp: unable to verify attachment")
|
return nil, errors.New("gopenpgp: unable to verify attachment")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,6 +204,58 @@ func DecryptBinaryMessageArmored(privateKey string, passphrase []byte, ciphertex
|
||||||
return message.GetBinary(), nil
|
return message.GetBinary(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncryptSignArmoredDetached takes a public key for encryption,
|
||||||
|
// a private key and its passphrase for signature, and the plaintext data
|
||||||
|
// Returns an armored ciphertext and a detached armored signature.
|
||||||
|
func EncryptSignArmoredDetached(
|
||||||
|
publicKey, privateKey string,
|
||||||
|
passphrase, plainData []byte,
|
||||||
|
) (ciphertext, signature string, err error) {
|
||||||
|
var message *crypto.PlainMessage = crypto.NewPlainMessage(plainData)
|
||||||
|
|
||||||
|
// We encrypt the message
|
||||||
|
if ciphertext, err = encryptMessageArmored(publicKey, message); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We sign the message
|
||||||
|
if signature, err = signDetachedArmored(privateKey, passphrase, message); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ciphertext, signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptVerifyArmoredDetached decrypts an armored pgp message
|
||||||
|
// and verify a detached armored signature
|
||||||
|
// given a publicKey, and a privateKey with its passphrase.
|
||||||
|
// Returns the plain data or an error on
|
||||||
|
// signature verification failure.
|
||||||
|
func DecryptVerifyArmoredDetached(
|
||||||
|
publicKey, privateKey string,
|
||||||
|
passphrase []byte,
|
||||||
|
ciphertext string,
|
||||||
|
armoredSignature string,
|
||||||
|
) (plainData []byte, err error) {
|
||||||
|
var message *crypto.PlainMessage
|
||||||
|
|
||||||
|
// We decrypt the message
|
||||||
|
if message, err = decryptMessageArmored(privateKey, passphrase, ciphertext); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We verify the signature
|
||||||
|
var check bool
|
||||||
|
if check, err = verifyDetachedArmored(publicKey, message, armoredSignature); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !check {
|
||||||
|
return nil, errors.New("gopenpgp: unable to verify message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.GetBinary(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func encryptMessageArmored(key string, message *crypto.PlainMessage) (string, error) {
|
func encryptMessageArmored(key string, message *crypto.PlainMessage) (string, error) {
|
||||||
publicKey, err := crypto.NewKeyFromArmored(key)
|
publicKey, err := crypto.NewKeyFromArmored(key)
|
||||||
if publicKey.IsPrivate() {
|
if publicKey.IsPrivate() {
|
||||||
|
|
@ -304,3 +325,96 @@ func decryptMessageArmored(privateKey string, passphrase []byte, ciphertext stri
|
||||||
|
|
||||||
return message, nil
|
return message, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signDetachedArmored(privateKey string, passphrase []byte, message *crypto.PlainMessage) (signature string, err error) {
|
||||||
|
privateKeyObj, err := crypto.NewKeyFromArmored(privateKey)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKeyUnlocked, err := privateKeyObj.Unlock(passphrase)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer privateKeyUnlocked.ClearPrivateParams()
|
||||||
|
|
||||||
|
privateKeyRing, err := crypto.NewKeyRing(privateKeyUnlocked)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
detachedSignature, err := privateKeyRing.SignDetached(message)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
armoredSignature, err := detachedSignature.GetArmored()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return armoredSignature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyDetachedArmored(publicKey string, message *crypto.PlainMessage, armoredSignature string) (check bool, err error) {
|
||||||
|
var publicKeyObj *crypto.Key
|
||||||
|
var publicKeyRing *crypto.KeyRing
|
||||||
|
var detachedSignature *crypto.PGPSignature
|
||||||
|
// We prepare the public key for signature verification
|
||||||
|
if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if publicKeyObj.IsPrivate() {
|
||||||
|
publicKeyObj, err = publicKeyObj.ToPublic()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We verify the signature
|
||||||
|
if detachedSignature, err = crypto.NewPGPSignatureFromArmored(armoredSignature); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if publicKeyRing.VerifyDetached(message, detachedSignature, crypto.GetUnixTime()) != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptAttachment(
|
||||||
|
privateKey string,
|
||||||
|
passphrase, keyPacket, dataPacket []byte,
|
||||||
|
) (message *crypto.PlainMessage, err error) {
|
||||||
|
var privateKeyObj, unlockedKeyObj *crypto.Key
|
||||||
|
var privateKeyRing *crypto.KeyRing
|
||||||
|
|
||||||
|
packets := crypto.NewPGPSplitMessage(keyPacket, dataPacket)
|
||||||
|
|
||||||
|
// prepare the private key for decryption
|
||||||
|
if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer unlockedKeyObj.ClearPrivateParams()
|
||||||
|
|
||||||
|
if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if message, err = privateKeyRing.DecryptAttachment(packets); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return message, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package helper
|
package helper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||||
|
|
@ -154,3 +155,64 @@ func TestArmoredBinaryMessageEncryption(t *testing.T) {
|
||||||
|
|
||||||
assert.Exactly(t, plainData, decrypted)
|
assert.Exactly(t, plainData, decrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncryptSignArmoredDetached(t *testing.T) {
|
||||||
|
plainData := []byte("Secret message")
|
||||||
|
privateKeyString := readTestFile("keyring_privateKey", false)
|
||||||
|
privateKey, err := crypto.NewKeyFromArmored(privateKeyString)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Error reading the test private key: ", err)
|
||||||
|
}
|
||||||
|
publicKeyString, err := privateKey.GetArmoredPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Error reading the test public key: ", err)
|
||||||
|
}
|
||||||
|
armoredCiphertext, armoredSignature, err := EncryptSignArmoredDetached(
|
||||||
|
publicKeyString,
|
||||||
|
privateKeyString,
|
||||||
|
testMailboxPassword, // Password defined in base_test
|
||||||
|
plainData,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error while encrypting and signing, got:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := DecryptVerifyArmoredDetached(
|
||||||
|
publicKeyString,
|
||||||
|
privateKeyString,
|
||||||
|
testMailboxPassword,
|
||||||
|
armoredCiphertext,
|
||||||
|
armoredSignature,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error while decrypting and verifying, got:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(decrypted, plainData) {
|
||||||
|
t.Error("Decrypted is not equal to the plaintext")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, modifiedSignature, err := EncryptSignArmoredDetached(
|
||||||
|
publicKeyString,
|
||||||
|
privateKeyString,
|
||||||
|
testMailboxPassword, // Password defined in base_test
|
||||||
|
[]byte("Different message"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Expected no error while encrypting and signing, got:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = DecryptVerifyArmoredDetached(
|
||||||
|
publicKeyString,
|
||||||
|
privateKeyString,
|
||||||
|
testMailboxPassword,
|
||||||
|
armoredCiphertext,
|
||||||
|
modifiedSignature,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Expected an error while decrypting and verifying with a wrong signature")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,3 +79,20 @@ func GetJsonSHA256Fingerprints(publicKey string) ([]byte, error) {
|
||||||
|
|
||||||
return json.Marshal(key.GetSHA256Fingerprints())
|
return json.Marshal(key.GetSHA256Fingerprints())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EncryptSignArmoredDetachedMobileResult struct {
|
||||||
|
Ciphertext, Signature string
|
||||||
|
}
|
||||||
|
|
||||||
|
//EncryptSignArmoredDetachedMobile wraps the EncryptSignArmoredDetached method
|
||||||
|
//to have only one return argument for mobile.
|
||||||
|
func EncryptSignArmoredDetachedMobile(
|
||||||
|
publicKey, privateKey string,
|
||||||
|
passphrase, plainData []byte,
|
||||||
|
) (wrappedTuple *EncryptSignArmoredDetachedMobileResult, err error) {
|
||||||
|
ciphertext, signature, err := EncryptSignArmoredDetached(publicKey, privateKey, passphrase, plainData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &EncryptSignArmoredDetachedMobileResult{ciphertext, signature}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue