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,
|
||||
armoredSignature string,
|
||||
) (plainData []byte, err error) {
|
||||
var publicKeyObj, privateKeyObj, unlockedKeyObj *crypto.Key
|
||||
var publicKeyRing, privateKeyRing *crypto.KeyRing
|
||||
var detachedSignature *crypto.PGPSignature
|
||||
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 {
|
||||
// We decrypt the attachment
|
||||
message, err := decryptAttachment(privateKey, passphrase, keyPacket, dataPacket)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if !check {
|
||||
return nil, errors.New("gopenpgp: unable to verify attachment")
|
||||
}
|
||||
|
||||
|
|
@ -235,6 +204,58 @@ func DecryptBinaryMessageArmored(privateKey string, passphrase []byte, ciphertex
|
|||
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) {
|
||||
publicKey, err := crypto.NewKeyFromArmored(key)
|
||||
if publicKey.IsPrivate() {
|
||||
|
|
@ -304,3 +325,96 @@ func decryptMessageArmored(privateKey string, passphrase []byte, ciphertext stri
|
|||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||
|
|
@ -154,3 +155,64 @@ func TestArmoredBinaryMessageEncryption(t *testing.T) {
|
|||
|
||||
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())
|
||||
}
|
||||
|
||||
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