2018-09-11 11:09:28 +02:00
package crypto
2018-06-04 16:05:14 -07:00
import (
"bytes"
"errors"
"io/ioutil"
"time"
2018-11-01 17:03:43 +01:00
armorUtils "github.com/ProtonMail/go-pm-crypto/armor"
"github.com/ProtonMail/go-pm-crypto/internal"
"github.com/ProtonMail/go-pm-crypto/models"
2018-06-04 16:05:14 -07:00
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
2018-07-31 01:00:45 +02:00
errors2 "golang.org/x/crypto/openpgp/errors"
2018-09-19 11:52:14 +02:00
"golang.org/x/crypto/openpgp/packet"
2018-07-31 01:00:45 +02:00
"math"
2018-09-11 11:09:28 +02:00
)
2018-06-04 16:05:14 -07:00
// DecryptMessage decrypt encrypted message use private key (string )
// encryptedText : string armored encrypted
// privateKey : armored private use to decrypt message
// passphrase : match with private key to decrypt message
2018-11-09 02:03:19 +01:00
func ( pm * PmCrypto ) DecryptMessageStringKey ( encryptedText string , privateKey string , passphrase string ) ( string , error ) {
2018-09-19 11:52:14 +02:00
privKeyRaw , err := armorUtils . Unarmor ( privateKey )
2018-06-04 16:05:14 -07:00
if err != nil {
return "" , err
}
2018-11-09 02:03:19 +01:00
privKeyReader := bytes . NewReader ( privKeyRaw )
privKeyEntries , err := openpgp . ReadKeyRing ( privKeyReader )
if err != nil {
return "" , err
}
return pm . DecryptMessage ( encryptedText , & KeyRing { entities : privKeyEntries } , passphrase )
2018-06-04 16:05:14 -07:00
}
// DecryptMessageBinKey decrypt encrypted message use private key (bytes )
// encryptedText : string armored encrypted
2018-06-05 14:50:54 -07:00
// privateKey : unarmored private use to decrypt message could be mutiple keys
2018-06-04 16:05:14 -07:00
// passphrase : match with private key to decrypt message
2018-11-09 02:08:39 +01:00
func ( pm * PmCrypto ) DecryptMessage ( encryptedText string , privateKey * KeyRing , passphrase string ) ( string , error ) {
2018-06-04 16:05:14 -07:00
2018-11-21 21:11:30 +01:00
md , err := decryptCore ( encryptedText , nil , privateKey , passphrase , pm . getTimeGenerator ( ) )
2018-06-04 16:05:14 -07:00
if err != nil {
return "" , err
}
decrypted := md . UnverifiedBody
b , err := ioutil . ReadAll ( decrypted )
if err != nil {
return "" , err
}
println ( 4 )
return string ( b ) , nil
}
2018-11-21 21:11:30 +01:00
func decryptCore ( encryptedText string , additionalEntries openpgp . EntityList , privKey * KeyRing , passphrase string , timeFunc func ( ) time . Time ) ( * openpgp . MessageDetails , error ) {
2018-06-04 16:05:14 -07:00
rawPwd := [ ] byte ( passphrase )
2018-11-21 21:11:30 +01:00
privKey . Unlock ( rawPwd )
2018-06-04 16:05:14 -07:00
2018-11-21 21:11:30 +01:00
privKeyEntries := privKey . entities
for _ , entity := range privKey . entities {
privKeyEntries = append ( privKeyEntries , entity )
2018-06-04 16:05:14 -07:00
}
2018-11-05 22:55:45 +01:00
if additionalEntries != nil {
for _ , e := range additionalEntries {
privKeyEntries = append ( privKeyEntries , e )
}
}
encryptedio , err := internal . Unarmor ( encryptedText )
if err != nil {
return nil , err
}
config := & packet . Config { Time : timeFunc }
md , err := openpgp . ReadMessage ( encryptedio . Body , privKeyEntries , nil , config )
return md , err
}
2018-11-09 13:03:46 +01:00
func ( pm * PmCrypto ) DecryptMessageVerify ( encryptedText string , verifierKey * KeyRing , privateKeyRing * KeyRing , passphrase string , verifyTime int64 ) ( * models . DecryptSignedVerify , error ) {
// DecryptMessageVerifyBinKeyPrivBinKeys decrypt message and verify the signature
// verifierKey []byte: unarmored verifier keys
// privateKey []byte: unarmored private key to decrypt. could be mutiple
2018-11-05 22:55:45 +01:00
2018-09-11 11:09:28 +02:00
out := & models . DecryptSignedVerify { }
2018-06-04 16:05:14 -07:00
out . Verify = failed
2018-06-05 14:50:54 -07:00
var verifierEntries openpgp . EntityList
2018-11-09 13:03:46 +01:00
if len ( verifierKey . entities ) == 0 {
2018-06-04 16:05:14 -07:00
out . Verify = noVerifier
}
2018-11-21 21:11:30 +01:00
md , err := decryptCore ( encryptedText , verifierEntries , privateKeyRing , passphrase , func ( ) time . Time { return time . Unix ( 0 , 0 ) } ) // TODO: I doubt this time is correct
2018-06-04 16:05:14 -07:00
decrypted := md . UnverifiedBody
b , err := ioutil . ReadAll ( decrypted )
if err != nil {
return nil , err
}
2018-07-31 01:00:45 +02:00
processSignatureExpiration ( md , verifyTime )
2018-06-04 16:05:14 -07:00
out . Plaintext = string ( b )
if md . IsSigned {
if md . SignedBy != nil {
2018-11-09 13:03:46 +01:00
if len ( verifierKey . entities ) > 0 {
matches := verifierKey . entities . KeysById ( md . SignedByKeyId )
2018-06-05 14:50:54 -07:00
if len ( matches ) > 0 {
if md . SignatureError == nil {
out . Verify = ok
} else {
out . Message = md . SignatureError . Error ( )
out . Verify = failed
}
}
2018-06-04 16:05:14 -07:00
} else {
2018-06-05 14:50:54 -07:00
out . Verify = noVerifier
2018-06-04 16:05:14 -07:00
}
} else {
out . Verify = noVerifier
}
} else {
out . Verify = notSigned
}
return out , nil
}
2018-07-31 01:00:45 +02:00
// Handle signature time verification manually, so we can add a margin to the creationTime check.
func processSignatureExpiration ( md * openpgp . MessageDetails , verifyTime int64 ) {
if md . SignatureError == errors2 . ErrSignatureExpired {
if verifyTime > 0 {
created := md . Signature . CreationTime . Unix ( )
expires := int64 ( math . MaxInt64 )
if md . Signature . KeyLifetimeSecs != nil {
expires = int64 ( * md . Signature . KeyLifetimeSecs ) + created
}
2018-09-19 11:52:14 +02:00
if created - internal . CreationTimeOffset <= verifyTime && verifyTime <= expires {
2018-07-31 01:00:45 +02:00
md . SignatureError = nil
}
} else {
// verifyTime = 0: time check disabled, everything is okay
md . SignatureError = nil
}
}
}
2018-11-09 02:03:19 +01:00
//EncryptMessageWithPassword encrypt a plain text to pgp message with a password
//plainText string: clear text
//output string: armored pgp message
func ( pm * PmCrypto ) EncryptMessageWithPassword ( plainText string , password string ) ( string , error ) {
var outBuf bytes . Buffer
w , err := armor . Encode ( & outBuf , armorUtils . PGP_MESSAGE_HEADER , internal . ArmorHeaders )
if err != nil {
return "" , err
}
config := & packet . Config { Time : pm . getTimeGenerator ( ) }
plaintext , err := openpgp . SymmetricallyEncrypt ( w , [ ] byte ( password ) , nil , config )
if err != nil {
return "" , err
}
message := [ ] byte ( plainText )
_ , err = plaintext . Write ( message )
2018-06-04 16:05:14 -07:00
if err != nil {
return "" , err
}
2018-11-09 02:03:19 +01:00
err = plaintext . Close ( )
if err != nil {
return "" , err
}
w . Close ( )
return outBuf . String ( ) , nil
2018-06-04 16:05:14 -07:00
}
2018-06-05 14:50:54 -07:00
// EncryptMessageBinKey encrypt message with unarmored public key, if pass private key and passphrase will also sign the message
2018-06-04 16:05:14 -07:00
// publicKey : bytes unarmored public key
// plainText : the input
// privateKey : optional required when you want to sign
// passphrase : optional required when you pass the private key and this passphrase must could decrypt the private key
2018-11-09 02:03:19 +01:00
func ( pm * PmCrypto ) EncryptMessage ( plainText string , publicKey * KeyRing , privateKey * KeyRing , passphrase string , trim bool ) ( string , error ) {
2018-06-04 16:05:14 -07:00
2018-06-05 15:26:55 -07:00
if trim {
2018-09-11 11:09:28 +02:00
plainText = internal . TrimNewlines ( plainText )
2018-06-05 15:26:55 -07:00
}
2018-06-04 16:05:14 -07:00
var outBuf bytes . Buffer
2018-11-05 22:55:45 +01:00
w , err := armor . Encode ( & outBuf , armorUtils . PGP_MESSAGE_HEADER , internal . ArmorHeaders )
2018-06-04 16:05:14 -07:00
if err != nil {
return "" , err
}
var signEntity * openpgp . Entity
2018-11-09 02:03:19 +01:00
if len ( passphrase ) > 0 && len ( privateKey . entities ) > 0 {
2018-06-04 16:05:14 -07:00
2018-11-21 21:11:30 +01:00
signEntity := privateKey . GetSigningEntity ( passphrase )
2018-06-04 16:05:14 -07:00
if signEntity == nil {
2018-09-19 11:52:14 +02:00
return "" , errors . New ( "cannot sign message, signer key is not unlocked" )
2018-06-04 16:05:14 -07:00
}
}
2018-11-09 02:03:19 +01:00
ew , err := EncryptCore ( w , publicKey . entities , signEntity , "" , false , pm . getTimeGenerator ( ) )
2018-06-04 16:05:14 -07:00
_ , _ = ew . Write ( [ ] byte ( plainText ) )
ew . Close ( )
w . Close ( )
return outBuf . String ( ) , nil
}