wrapper for mobile
This commit is contained in:
commit
8d300e4782
17 changed files with 1763 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.DS_Store
|
||||||
|
bin
|
||||||
|
vendor
|
||||||
|
.vscode
|
||||||
61
armor.go
Normal file
61
armor.go
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp/armor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AromrType ...
|
||||||
|
type AromrType string
|
||||||
|
|
||||||
|
func (at AromrType) string() string {
|
||||||
|
return string(at)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
pgpMessageType AromrType = "PGP MESSAGE"
|
||||||
|
pgpPublicBlockType AromrType = "PGP PUBLIC KEY BLOCK"
|
||||||
|
pgpPrivateBlockType AromrType = "PGP PRIVATE KEY BLOCK"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArmorKey make bytes input key to armor format
|
||||||
|
func ArmorKey(input []byte) (string, error) {
|
||||||
|
return ArmorWithType(input, pgpPublicBlockType.string())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArmorWithType make bytes input to armor format
|
||||||
|
func ArmorWithType(input []byte, armorType string) (string, error) {
|
||||||
|
var b bytes.Buffer
|
||||||
|
w, err := armor.Encode(&b, armorType, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
_, err = w.Write(input)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
w.Close()
|
||||||
|
return b.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnArmor an armored key to bytes key
|
||||||
|
func UnArmor(input string) ([]byte, error) {
|
||||||
|
b, err := unArmor(input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ioutil.ReadAll(b.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unArmor(input string) (*armor.Block, error) {
|
||||||
|
io := strings.NewReader(input)
|
||||||
|
b, err := armor.Decode(io)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
|
||||||
|
}
|
||||||
158
attachment.go
Normal file
158
attachment.go
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
"golang.org/x/crypto/openpgp/armor"
|
||||||
|
"golang.org/x/crypto/openpgp/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
//EncryptAttachmentBinKey ...
|
||||||
|
func (o *OpenPGP) EncryptAttachmentBinKey(plainData []byte, fileName string, publicKey []byte) (*EncryptedSplit, error) {
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
w, err := armor.Encode(&outBuf, pgpMessageType.string(), armorHeader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hints := &openpgp.FileHints{
|
||||||
|
FileName: fileName,
|
||||||
|
}
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
|
||||||
|
ew, err := openpgp.Encrypt(w, pubKeyEntries, nil, hints, config)
|
||||||
|
|
||||||
|
_, _ = ew.Write(plainData)
|
||||||
|
ew.Close()
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
splited, err := SeparateKeyAndData(outBuf.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
splited.Algo = "aes256"
|
||||||
|
return splited, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//EncryptAttachment ...
|
||||||
|
func (o *OpenPGP) EncryptAttachment(plainData []byte, fileName string, publicKey string) (*EncryptedSplit, error) {
|
||||||
|
rawPubKey, err := UnArmor(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return o.EncryptAttachmentBinKey(plainData, fileName, rawPubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
//DecryptAttachmentBinKey ...
|
||||||
|
//keyPacket
|
||||||
|
//dataPacket
|
||||||
|
//privateKeys could be mutiple private keys
|
||||||
|
func (o *OpenPGP) DecryptAttachmentBinKey(keyPacket []byte, dataPacket []byte, privateKeys []byte, passphrase string) ([]byte, error) {
|
||||||
|
privKeyRaw := bytes.NewReader(privateKeys)
|
||||||
|
privKeyEntries, err := openpgp.ReadKeyRing(privKeyRaw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawPwd := []byte(passphrase)
|
||||||
|
for _, e := range privKeyEntries {
|
||||||
|
|
||||||
|
if e.PrivateKey != nil && e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt(rawPwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sub := range e.Subkeys {
|
||||||
|
if sub.PrivateKey != nil && sub.PrivateKey.Encrypted {
|
||||||
|
sub.PrivateKey.Decrypt(rawPwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyReader := bytes.NewReader(keyPacket)
|
||||||
|
dataReader := bytes.NewReader(dataPacket)
|
||||||
|
|
||||||
|
encryptedReader := io.MultiReader(keyReader, dataReader)
|
||||||
|
|
||||||
|
md, err := openpgp.ReadMessage(encryptedReader, privKeyEntries, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := md.UnverifiedBody
|
||||||
|
b, err := ioutil.ReadAll(decrypted)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//DecryptAttachment ...
|
||||||
|
func (o *OpenPGP) DecryptAttachment(keyPacket []byte, dataPacket []byte, privateKey string, passphrase string) ([]byte, error) {
|
||||||
|
rawPrivKey, err := UnArmor(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return o.DecryptAttachmentBinKey(keyPacket, dataPacket, rawPrivKey, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
//EncryptAttachmentWithPassword ...
|
||||||
|
func (o *OpenPGP) EncryptAttachmentWithPassword(plainData []byte, password string) (string, error) {
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
w, err := armor.Encode(&outBuf, pgpMessageType.string(), armorHeader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext, err := openpgp.SymmetricallyEncrypt(w, []byte(password), nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = plaintext.Write(plainData)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = plaintext.Close()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//DecryptAttachmentWithPassword ...
|
||||||
|
func (o *OpenPGP) DecryptAttachmentWithPassword(keyPacket []byte, dataPacket []byte, password string) ([]byte, error) {
|
||||||
|
|
||||||
|
encrypted := append(keyPacket, dataPacket...)
|
||||||
|
|
||||||
|
encryptedReader := bytes.NewReader(encrypted)
|
||||||
|
|
||||||
|
var prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
||||||
|
return []byte(password), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := openpgp.ReadMessage(encryptedReader, nil, prompt, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBuf := bytes.NewBuffer(nil)
|
||||||
|
_, err = io.Copy(messageBuf, md.UnverifiedBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageBuf.Bytes(), nil
|
||||||
|
}
|
||||||
27
build.sh
Executable file
27
build.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_LOCATION=$(cd $(dirname $0);echo $PWD)
|
||||||
|
|
||||||
|
OUTPUT_PATH="bin"
|
||||||
|
ANDROID_OUT=${OUTPUT_PATH}/"Android"
|
||||||
|
IOS_OUT=${OUTPUT_PATH}/"iOS"
|
||||||
|
|
||||||
|
# CHECK="${1-0}"
|
||||||
|
# if [ ${CHECK} -eq "1" ]; then
|
||||||
|
printf "\e[0;32mStart Building iOS framework .. Location: ${IOS_OUT} \033[0m\n\n"
|
||||||
|
|
||||||
|
gomobile bind -target ios -o ${IOS_OUT}/PM.framework
|
||||||
|
|
||||||
|
|
||||||
|
printf "\e[0;32mStart Building Android lib .. Location: ${ANDROID_OUT} \033[0m\n\n"
|
||||||
|
|
||||||
|
gomobile bind -target android -o ${ANDROID_OUT}/PM.aar
|
||||||
|
|
||||||
|
|
||||||
|
printf "\e[0;32mInstalling frameworks. \033[0m\n\n"
|
||||||
|
|
||||||
|
cp -rf ${IOS_OUT}/PM.framework /Users/Yanfeng/Documents/ProtonMailGit/protonmail_ios/ProtonMail/
|
||||||
|
|
||||||
|
printf "\e[0;32mAll Done. \033[0m\n\n"
|
||||||
|
|
||||||
|
|
||||||
23
common.go
Normal file
23
common.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
var armorHeader = map[string]string{
|
||||||
|
"Version": "OpenPGP Mobile 0.0.1 (" + Version() + ")",
|
||||||
|
"Comment": "https://protonmail.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key ... add later
|
||||||
|
// protonmail key object
|
||||||
|
type Key struct {
|
||||||
|
KeyID string
|
||||||
|
PublicKey string
|
||||||
|
PrivateKey string
|
||||||
|
FingerPrint string
|
||||||
|
}
|
||||||
|
|
||||||
|
//Address ... add later protonmail address object
|
||||||
|
type Address struct {
|
||||||
|
// address_id : string;
|
||||||
|
// #optional
|
||||||
|
// address_name : string;
|
||||||
|
keys []Key
|
||||||
|
}
|
||||||
32
fingerprint.go
Normal file
32
fingerprint.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetFingerprint get a armored public key fingerprint
|
||||||
|
func GetFingerprint(publicKey string) (string, error) {
|
||||||
|
rawPubKey, err := UnArmor(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return GetFingerprintBinKey(rawPubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFingerprintBinKey get a unarmored public key fingerprint
|
||||||
|
func GetFingerprintBinKey(publicKey []byte) (string, error) {
|
||||||
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, e := range pubKeyEntries {
|
||||||
|
fp := e.PrimaryKey.Fingerprint
|
||||||
|
return hex.EncodeToString(fp[:]), nil
|
||||||
|
}
|
||||||
|
return "", errors.New("Can't find public key")
|
||||||
|
}
|
||||||
26
glide.lock
generated
Normal file
26
glide.lock
generated
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
hash: 217e5bc8c4d3160eeddd18dda7f8f8785f1b2b7f2ca58779b94ed8fd91ab226d
|
||||||
|
updated: 2018-06-04T16:04:51.812734-07:00
|
||||||
|
imports:
|
||||||
|
- name: golang.org/x/crypto
|
||||||
|
version: d36f3ee340e0aa6549738d42e0cb9139c902d7fd
|
||||||
|
repo: https://github.com/ProtonMail/crypto.git
|
||||||
|
subpackages:
|
||||||
|
- bitcurves
|
||||||
|
- brainpool
|
||||||
|
- cast5
|
||||||
|
- curve25519
|
||||||
|
- ed25519
|
||||||
|
- ed25519/internal/edwards25519
|
||||||
|
- openpgp
|
||||||
|
- openpgp/aes/keywrap
|
||||||
|
- openpgp/armor
|
||||||
|
- openpgp/clearsign
|
||||||
|
- openpgp/ecdh
|
||||||
|
- openpgp/elgamal
|
||||||
|
- openpgp/errors
|
||||||
|
- openpgp/internal/algorithm
|
||||||
|
- openpgp/internal/ecc
|
||||||
|
- openpgp/internal/encoding
|
||||||
|
- openpgp/packet
|
||||||
|
- openpgp/s2k
|
||||||
|
testImports: []
|
||||||
5
glide.yaml
Normal file
5
glide.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package: pm
|
||||||
|
import:
|
||||||
|
- package: golang.org/x/crypto
|
||||||
|
version: master
|
||||||
|
repo: https://github.com/ProtonMail/crypto.git
|
||||||
298
key.go
Normal file
298
key.go
Normal file
|
|
@ -0,0 +1,298 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
"golang.org/x/crypto/openpgp/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
//EncryptedSplit when encrypt attachemt
|
||||||
|
type EncryptedSplit struct {
|
||||||
|
DataPacket []byte
|
||||||
|
KeyPacket []byte
|
||||||
|
Algo string
|
||||||
|
}
|
||||||
|
|
||||||
|
//SessionSplit splited session
|
||||||
|
type SessionSplit struct {
|
||||||
|
Session []byte
|
||||||
|
Algo string
|
||||||
|
}
|
||||||
|
|
||||||
|
//EncryptedSigned encrypt_sign_package
|
||||||
|
type EncryptedSigned struct {
|
||||||
|
Encrypted string
|
||||||
|
Signature string
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ok = 0
|
||||||
|
notSigned = 1
|
||||||
|
noVerifier = 2
|
||||||
|
failed = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
//DecryptSignedVerify decrypt_sign_verify
|
||||||
|
type DecryptSignedVerify struct {
|
||||||
|
//clear text
|
||||||
|
Plaintext string
|
||||||
|
//bitmask verify status : 0
|
||||||
|
Verify int
|
||||||
|
//error message if verify failed
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
//CheckPassphrase check is private key passphrase ok
|
||||||
|
func CheckPassphrase(privateKey string, passphrase string) bool {
|
||||||
|
privKeyReader := strings.NewReader(privateKey)
|
||||||
|
entries, err := openpgp.ReadArmoredKeyRing(privKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys []*packet.PrivateKey
|
||||||
|
|
||||||
|
for _, e := range entries {
|
||||||
|
keys = append(keys, e.PrivateKey)
|
||||||
|
}
|
||||||
|
var decryptError error
|
||||||
|
var n int
|
||||||
|
for _, key := range keys {
|
||||||
|
if !key.Encrypted {
|
||||||
|
continue // Key already decrypted
|
||||||
|
}
|
||||||
|
if decryptError = key.Decrypt([]byte(passphrase)); decryptError == nil {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//IsKeyExpiredBin ...
|
||||||
|
func (o *OpenPGP) IsKeyExpiredBin(publicKey []byte) (bool, error) {
|
||||||
|
now := o.getNow()
|
||||||
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
candidateSubkey := -1
|
||||||
|
for _, e := range pubKeyEntries {
|
||||||
|
var maxTime time.Time
|
||||||
|
for i, subkey := range e.Subkeys {
|
||||||
|
if subkey.Sig.FlagsValid &&
|
||||||
|
subkey.Sig.FlagEncryptCommunications &&
|
||||||
|
subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
|
||||||
|
!subkey.Sig.KeyExpired(now) &&
|
||||||
|
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
|
||||||
|
candidateSubkey = i
|
||||||
|
maxTime = subkey.Sig.CreationTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if candidateSubkey != -1 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have any candidate subkeys for encryption and
|
||||||
|
// the primary key doesn't have any usage metadata then we
|
||||||
|
// assume that the primary key is ok. Or, if the primary key is
|
||||||
|
// marked as ok to encrypt to, then we can obviously use it.
|
||||||
|
var firstIdentity *openpgp.Identity
|
||||||
|
for _, ident := range e.Identities {
|
||||||
|
if firstIdentity == nil {
|
||||||
|
firstIdentity = ident
|
||||||
|
}
|
||||||
|
if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
|
||||||
|
firstIdentity = ident
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if firstIdentity != nil {
|
||||||
|
i := firstIdentity
|
||||||
|
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
|
||||||
|
e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
|
||||||
|
!i.SelfSignature.KeyExpired(now) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, errors.New("keys expired")
|
||||||
|
}
|
||||||
|
|
||||||
|
//IsKeyExpired ....
|
||||||
|
// will user the cached time to check
|
||||||
|
func (o *OpenPGP) IsKeyExpired(publicKey string) (bool, error) {
|
||||||
|
rawPubKey, err := UnArmor(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return o.IsKeyExpiredBin(rawPubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateKey ...
|
||||||
|
// disabled now, will enable later
|
||||||
|
// #generat new key with email address. Fix the UserID issue in protonmail system. on Feb 28, 17
|
||||||
|
// #static generate_key_with_email(email : string, passphrase : string, bits : i32) : open_pgp_key;
|
||||||
|
// # generate new key
|
||||||
|
// #static generate_new_key(user_id : string, email : string, passphrase : string, bits : i32) : open_pgp_key;
|
||||||
|
func (o *OpenPGP) GenerateKey(userName string, domain string, passphrase string, keyType string, bits int) (string, error) {
|
||||||
|
|
||||||
|
if len(userName) <= 0 {
|
||||||
|
return "", errors.New("Invalid user name format")
|
||||||
|
}
|
||||||
|
if len(domain) <= 0 {
|
||||||
|
return "", errors.New("Invalid domain")
|
||||||
|
}
|
||||||
|
email := userName + "@" + domain
|
||||||
|
comments := ""
|
||||||
|
timeNow := func() time.Time {
|
||||||
|
return o.getNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &packet.Config{RSABits: bits, Time: timeNow}
|
||||||
|
newEntity, err := openpgp.NewEntity(email, comments, email, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := newEntity.SelfSign(nil); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawPwd := []byte(passphrase)
|
||||||
|
if newEntity.PrivateKey != nil && !newEntity.PrivateKey.Encrypted {
|
||||||
|
if err := newEntity.PrivateKey.Encrypt(rawPwd); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sub := range newEntity.Subkeys {
|
||||||
|
if sub.PrivateKey != nil && !sub.PrivateKey.Encrypted {
|
||||||
|
if err := sub.PrivateKey.Encrypt(rawPwd); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w := bytes.NewBuffer(nil)
|
||||||
|
if err := newEntity.SerializePrivateNoSign(w, nil); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
serialized := w.Bytes()
|
||||||
|
return ArmorWithType(serialized, pgpPrivateBlockType.string())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePrivateKeyPassphrase ...
|
||||||
|
func (o *OpenPGP) UpdatePrivateKeyPassphrase(privateKey string, oldPassphrase string, newPassphrase string) (string, error) {
|
||||||
|
|
||||||
|
privKey := strings.NewReader(privateKey)
|
||||||
|
privKeyEntries, err := openpgp.ReadArmoredKeyRing(privKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
oldrawPwd := []byte(oldPassphrase)
|
||||||
|
newRawPwd := []byte(newPassphrase)
|
||||||
|
w := bytes.NewBuffer(nil)
|
||||||
|
for _, e := range privKeyEntries {
|
||||||
|
if e.PrivateKey != nil && e.PrivateKey.Encrypted {
|
||||||
|
if err := e.PrivateKey.Decrypt(oldrawPwd); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if e.PrivateKey != nil && !e.PrivateKey.Encrypted {
|
||||||
|
if err := e.PrivateKey.Encrypt(newRawPwd); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sub := range e.Subkeys {
|
||||||
|
if sub.PrivateKey != nil && sub.PrivateKey.Encrypted {
|
||||||
|
if err := sub.PrivateKey.Decrypt(oldrawPwd); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sub.PrivateKey != nil && !sub.PrivateKey.Encrypted {
|
||||||
|
if err := sub.PrivateKey.Encrypt(newRawPwd); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := e.SerializePrivateNoSign(w, nil); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serialized := w.Bytes()
|
||||||
|
return ArmorWithType(serialized, pgpPrivateBlockType.string())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKey get a public key from a private key
|
||||||
|
func PublicKey(privateKey string) (string, error) {
|
||||||
|
privKeyReader := strings.NewReader(privateKey)
|
||||||
|
entries, err := openpgp.ReadArmoredKeyRing(privKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
for _, e := range entries {
|
||||||
|
e.Serialize(&outBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
outString, err := ArmorKey(outBuf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return outString, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKeyBinOut get a public key from a private key
|
||||||
|
func PublicKeyBinOut(privateKey string) ([]byte, error) {
|
||||||
|
privKeyReader := strings.NewReader(privateKey)
|
||||||
|
entries, err := openpgp.ReadArmoredKeyRing(privKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
for _, e := range entries {
|
||||||
|
e.Serialize(&outBuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckKey print out the key and subkey fingerprint
|
||||||
|
func CheckKey(pubKey string) (string, error) {
|
||||||
|
pubKeyReader := strings.NewReader(pubKey)
|
||||||
|
entries, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range entries {
|
||||||
|
for _, subKey := range e.Subkeys {
|
||||||
|
if !subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications {
|
||||||
|
|
||||||
|
println("SubKey:" + hex.EncodeToString(subKey.PublicKey.Fingerprint[:]))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("PrimaryKey:" + hex.EncodeToString(e.PrimaryKey.Fingerprint[:]))
|
||||||
|
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
322
message.go
Normal file
322
message.go
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
"golang.org/x/crypto/openpgp/armor"
|
||||||
|
"golang.org/x/crypto/openpgp/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
func (o *OpenPGP) DecryptMessage(encryptedText string, privateKey string, passphrase string) (string, error) {
|
||||||
|
privKeyRaw, err := UnArmor(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return o.DecryptMessageBinKey(encryptedText, privKeyRaw, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessageBinKey decrypt encrypted message use private key (bytes )
|
||||||
|
// encryptedText : string armored encrypted
|
||||||
|
// privateKey : unarmored private use to decrypt message
|
||||||
|
// passphrase : match with private key to decrypt message
|
||||||
|
func (o *OpenPGP) DecryptMessageBinKey(encryptedText string, privateKey []byte, passphrase string) (string, error) {
|
||||||
|
privKey := bytes.NewReader(privateKey)
|
||||||
|
privKeyEntries, err := openpgp.ReadKeyRing(privKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedio, err := unArmor(encryptedText)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawPwd := []byte(passphrase)
|
||||||
|
for _, e := range privKeyEntries {
|
||||||
|
if e.PrivateKey != nil && e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt(rawPwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sub := range e.Subkeys {
|
||||||
|
if sub.PrivateKey != nil && sub.PrivateKey.Encrypted {
|
||||||
|
sub.PrivateKey.Decrypt(rawPwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := openpgp.ReadMessage(encryptedio.Body, privKeyEntries, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := md.UnverifiedBody
|
||||||
|
b, err := ioutil.ReadAll(decrypted)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
println(4)
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encryptedText string, privateKey string, passphrase string) (string, error)
|
||||||
|
// decrypt_message_verify_single_key(private_key: string, passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
// decrypt_message_verify(passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
func (o *OpenPGP) DecryptMessageVerifyPrivbinkeys(encryptedText string, veriferKey string, privateKeys []byte, passphrase string, verifyTime int64) (*DecryptSignedVerify, error) {
|
||||||
|
|
||||||
|
if len(veriferKey) > 0 {
|
||||||
|
verifierRaw, err := UnArmor(veriferKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return o.decryptMessageVerifyAllBin(encryptedText, verifierRaw, privateKeys, passphrase, verifyTime)
|
||||||
|
}
|
||||||
|
return o.decryptMessageVerifyAllBin(encryptedText, nil, privateKeys, passphrase, verifyTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encryptedText string, privateKey string, passphrase string) (string, error)
|
||||||
|
// decrypt_message_verify_single_key(private_key: string, passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
// decrypt_message_verify(passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
func (o *OpenPGP) DecryptMessageVerifyBinKeyPrivbinkeys(encryptedText string, veriferKey []byte, privateKeys []byte, passphrase string, verifyTime int64) (*DecryptSignedVerify, error) {
|
||||||
|
return o.decryptMessageVerifyAllBin(encryptedText, veriferKey, privateKeys, passphrase, verifyTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encryptedText string, privateKey string, passphrase string) (string, error)
|
||||||
|
// decrypt_message_verify_single_key(private_key: string, passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
// decrypt_message_verify(passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
func (o *OpenPGP) DecryptMessageVerify(encryptedText string, veriferKey string, privateKey string, passphrase string, verifyTime int64) (*DecryptSignedVerify, error) {
|
||||||
|
if len(veriferKey) > 0 {
|
||||||
|
verifierRaw, err := UnArmor(veriferKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return o.DecryptMessageVerifyBinKey(encryptedText, verifierRaw, privateKey, passphrase, verifyTime)
|
||||||
|
}
|
||||||
|
return o.DecryptMessageVerifyBinKey(encryptedText, nil, privateKey, passphrase, verifyTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encryptedText string, privateKey string, passphrase string) (string, error)
|
||||||
|
// decrypt_message_verify_single_key(private_key: string, passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
// decrypt_message_verify(passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
func (o *OpenPGP) DecryptMessageVerifyBinKey(encryptedText string, veriferKey []byte, privateKey string, passphrase string, verifyTime int64) (*DecryptSignedVerify, error) {
|
||||||
|
privateKeyRaw, err := UnArmor(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return o.decryptMessageVerifyAllBin(encryptedText, veriferKey, privateKeyRaw, passphrase, verifyTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encryptedText string, privateKey string, passphrase string) (string, error)
|
||||||
|
// decrypt_message_verify_single_key(private_key: string, passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
// decrypt_message_verify(passphras: string, encrypted : string, signature : string) : decrypt_sign_verify;
|
||||||
|
func (o *OpenPGP) decryptMessageVerifyAllBin(encryptedText string, veriferKey []byte, privateKey []byte, passphrase string, verifyTime int64) (*DecryptSignedVerify, error) {
|
||||||
|
privKey := bytes.NewReader(privateKey)
|
||||||
|
privKeyEntries, err := openpgp.ReadKeyRing(privKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawPwd := []byte(passphrase)
|
||||||
|
for _, e := range privKeyEntries {
|
||||||
|
|
||||||
|
if e.PrivateKey != nil && e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt(rawPwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sub := range e.Subkeys {
|
||||||
|
if sub.PrivateKey != nil && sub.PrivateKey.Encrypted {
|
||||||
|
sub.PrivateKey.Decrypt(rawPwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &DecryptSignedVerify{}
|
||||||
|
out.Verify = failed
|
||||||
|
|
||||||
|
if len(veriferKey) > 0 {
|
||||||
|
verifierReader := bytes.NewReader(veriferKey)
|
||||||
|
verifierEnties, err := openpgp.ReadKeyRing(verifierReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range verifierEnties {
|
||||||
|
privKeyEntries = append(privKeyEntries, e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Verify = noVerifier
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedio, err := unArmor(encryptedText)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &packet.Config{}
|
||||||
|
if verifyTime > 0 {
|
||||||
|
tm := time.Unix(verifyTime, 0)
|
||||||
|
config.Time = func() time.Time {
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := openpgp.ReadMessage(encryptedio.Body, privKeyEntries, nil, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted := md.UnverifiedBody
|
||||||
|
b, err := ioutil.ReadAll(decrypted)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Plaintext = string(b)
|
||||||
|
if md.IsSigned {
|
||||||
|
if md.SignedBy != nil {
|
||||||
|
if md.SignatureError == nil {
|
||||||
|
out.Verify = ok
|
||||||
|
} else {
|
||||||
|
out.Message = md.SignatureError.Error()
|
||||||
|
out.Verify = failed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Verify = noVerifier
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Verify = notSigned
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypt message with public key, if pass private key and passphrase will also sign the message
|
||||||
|
// publicKey : string armored 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
|
||||||
|
func (o *OpenPGP) EncryptMessage(plainText string, publicKey string, privateKey string, passphrase string, trim bool) (string, error) {
|
||||||
|
rawPubKey, err := UnArmor(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return o.EncryptMessageBinKey(plainText, rawPubKey, privateKey, passphrase, trim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessageBinKey encrypt message with public key, if pass private key and passphrase will also sign the message
|
||||||
|
// 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
|
||||||
|
func (o *OpenPGP) EncryptMessageBinKey(plainText string, publicKey []byte, privateKey string, passphrase string, trim bool) (string, error) {
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
w, err := armor.Encode(&outBuf, pgpMessageType.string(), armorHeader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var signEntity *openpgp.Entity
|
||||||
|
|
||||||
|
if len(passphrase) > 0 && len(privateKey) > 0 {
|
||||||
|
signerReader := strings.NewReader(privateKey)
|
||||||
|
signerEntries, err := openpgp.ReadArmoredKeyRing(signerReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range signerEntries {
|
||||||
|
// Entity.PrivateKey must be a signing key
|
||||||
|
if e.PrivateKey != nil {
|
||||||
|
if e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt([]byte(passphrase))
|
||||||
|
}
|
||||||
|
if !e.PrivateKey.Encrypted {
|
||||||
|
signEntity = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signEntity == nil {
|
||||||
|
return "", errors.New("cannot sign message, singer key is not unlocked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
|
||||||
|
ew, err := openpgp.Encrypt(w, pubKeyEntries, signEntity, nil, config)
|
||||||
|
|
||||||
|
_, _ = ew.Write([]byte(plainText))
|
||||||
|
ew.Close()
|
||||||
|
w.Close()
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//EncryptMessageWithPassword ...
|
||||||
|
func (o *OpenPGP) EncryptMessageWithPassword(plainText string, password string) (string, error) {
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
w, err := armor.Encode(&outBuf, pgpMessageType.string(), armorHeader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext, err := openpgp.SymmetricallyEncrypt(w, []byte(password), nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
message := []byte(plainText)
|
||||||
|
_, err = plaintext.Write(message)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = plaintext.Close()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//DecryptMessageWithPassword ...
|
||||||
|
func (o *OpenPGP) DecryptMessageWithPassword(encrypted string, password string) (string, error) {
|
||||||
|
|
||||||
|
encryptedio, err := unArmor(encrypted)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
||||||
|
return []byte(password), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := openpgp.ReadMessage(encryptedio.Body, nil, prompt, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBuf := bytes.NewBuffer(nil)
|
||||||
|
_, err = io.Copy(messageBuf, md.UnverifiedBody)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageBuf.String(), nil
|
||||||
|
}
|
||||||
0
notes.txt
Normal file
0
notes.txt
Normal file
38
openpgp.go
Normal file
38
openpgp.go
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
// OpenPGP strutature to manager mutiple address keys and user keys
|
||||||
|
type OpenPGP struct {
|
||||||
|
// key ring not in used
|
||||||
|
addresses []*Address
|
||||||
|
|
||||||
|
//lastestServerTime unix time cache
|
||||||
|
lastestServerTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// //AddAddress add a new address to key ring
|
||||||
|
// //add a new address into addresses list
|
||||||
|
// func (pgp *OpenPGP) AddAddress(address *Address) (bool, error) {
|
||||||
|
// return true, errors.New("this is not implemented yet, will add this later")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //RemoveAddress remove address from the keyring
|
||||||
|
// //
|
||||||
|
// //#remove a exsit address from the list based on address id
|
||||||
|
// func (pgp *OpenPGP) RemoveAddress(addressID string) (bool, error) {
|
||||||
|
// return true, errors.New("this is not implemented yet, will add this later")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //CleanAddresses clear all addresses in keyring
|
||||||
|
// func (pgp *OpenPGP) CleanAddresses() (bool, error) {
|
||||||
|
// return true, errors.New("this is not implemented yet, will add this later")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //EncryptMessage encrypt message use address id
|
||||||
|
// func (pgp *OpenPGP) EncryptMessage(addressID string, plainText string, passphrase string, trim bool) (string, error) {
|
||||||
|
// return "", errors.New("this is not implemented yet, will add this later")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //DecryptMessage decrypt message, this will lookup all keys
|
||||||
|
// func (pgp *OpenPGP) DecryptMessage(encryptText string, passphras string) (string, error) {
|
||||||
|
// return "", errors.New("this is not implemented yet, will add this later")
|
||||||
|
// }
|
||||||
52
readme.mk
Normal file
52
readme.mk
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
setup gomobile and build/bind the source code:
|
||||||
|
|
||||||
|
Gomobile repo: https://github.com/golang/mobile
|
||||||
|
Gomobile wiki: https://github.com/golang/go/wiki/Mobile
|
||||||
|
ProtonMail Openpgp: https://github.com/ProtonMail/crypto/tree/master/openpgp
|
||||||
|
|
||||||
|
1. Install Go: brew install go
|
||||||
|
2. Install Gomobile: go get golang.org/x/mobile/cmd/gomobile
|
||||||
|
//go get -u golang.org/x/mobile/cmd/...
|
||||||
|
3. Install Gobind: go install golang.org/x/mobile/cmd/gobind
|
||||||
|
3. Install android sdk and ndk use android studio
|
||||||
|
4. Set Env: export ANDROID_HOME="/AndroidSDK" #set your own path
|
||||||
|
5. Init gomobile: gomobile init -ndk /AndroidSDK/ndk-bundle/ #put your own ndk path
|
||||||
|
|
||||||
|
6. build examples:
|
||||||
|
gomobile build -target=android #or ios
|
||||||
|
|
||||||
|
bind examples:
|
||||||
|
gomobile bind -target ios -o frameworks/name.framework
|
||||||
|
gomobile bind -target android
|
||||||
|
|
||||||
|
the bind will create framework for ios and jar&aar file for android x86_64 arm arch
|
||||||
|
|
||||||
|
|
||||||
|
7. Project uses glide to setup vendor
|
||||||
|
|
||||||
|
OTHER NOTES:
|
||||||
|
two way bridge go & swift:
|
||||||
|
https://medium.com/@matryer/tutorial-calling-go-code-from-swift-on-ios-and-vice-versa-with-gomobile-7925620c17a4
|
||||||
|
|
||||||
|
|
||||||
|
SOME UNSOLVED ISSUES:
|
||||||
|
No Mips support but this is fine we don't support it anyway
|
||||||
|
https://github.com/golang/go/issues/23692 issue with atomic
|
||||||
|
EXC_BAD_ACCESS is hard to catch
|
||||||
|
https://github.com/golang/go/issues/21288 memory issue
|
||||||
|
https://github.com/golang/go/issues/21594 gradle issue
|
||||||
|
https://github.com/golang/go/issues/23307
|
||||||
|
https://github.com/golang/go/issues/20241
|
||||||
|
upload failed. we are using framework need to confirm this
|
||||||
|
https://github.com/golang/go/issues/17278 android load jni issue
|
||||||
|
https://github.com/golang/go/issues/17807 dlopen issue
|
||||||
|
https://github.com/golang/go/issues/18903 doesn't work well with vender
|
||||||
|
https://github.com/golang/go/issues/13438 bind issue
|
||||||
|
https://github.com/golang/go/issues/14332 build types issue
|
||||||
|
https://github.com/golang/go/issues/15956 no multiple independent bindings support
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The build.sh need to modify the path when you use it
|
||||||
364
session.go
Normal file
364
session.go
Normal file
|
|
@ -0,0 +1,364 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
"golang.org/x/crypto/openpgp/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
//RandomToken ...
|
||||||
|
func RandomToken() ([]byte, error) {
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
keySize := config.DefaultCipher.KeySize()
|
||||||
|
symKey := make([]byte, keySize)
|
||||||
|
if _, err := io.ReadFull(config.Random(), symKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return symKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomTokenWith ...
|
||||||
|
func RandomTokenWith(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, err
|
||||||
|
}
|
||||||
|
return symKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetSessionFromKeyPacketBinkeys get session key no encoding in and out
|
||||||
|
func GetSessionFromKeyPacketBinkeys(keyPackage []byte, privateKey []byte, passphrase string) (*SessionSplit, error) {
|
||||||
|
|
||||||
|
keyReader := bytes.NewReader(keyPackage)
|
||||||
|
packets := packet.NewReader(keyReader)
|
||||||
|
|
||||||
|
var p packet.Packet
|
||||||
|
var err error
|
||||||
|
if p, err = packets.Next(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ek := p.(*packet.EncryptedKey)
|
||||||
|
|
||||||
|
privKey := bytes.NewReader(privateKey)
|
||||||
|
privKeyEntries, err := openpgp.ReadKeyRing(privKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rawPwd := []byte(passphrase)
|
||||||
|
var decryptErr error
|
||||||
|
for _, key := range privKeyEntries.DecryptionKeys() {
|
||||||
|
priv := key.PrivateKey
|
||||||
|
if priv.Encrypted {
|
||||||
|
if err := priv.Decrypt(rawPwd); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if decryptErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return getSessionSplit(ek)
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetSessionFromKeyPacket get session key no encoding in and out
|
||||||
|
func GetSessionFromKeyPacket(keyPackage []byte, privateKey string, passphrase string) (*SessionSplit, error) {
|
||||||
|
|
||||||
|
keyReader := bytes.NewReader(keyPackage)
|
||||||
|
packets := packet.NewReader(keyReader)
|
||||||
|
|
||||||
|
var p packet.Packet
|
||||||
|
var err error
|
||||||
|
if p, err = packets.Next(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ek := p.(*packet.EncryptedKey)
|
||||||
|
|
||||||
|
privKey := strings.NewReader(privateKey)
|
||||||
|
privKeyEntries, err := openpgp.ReadArmoredKeyRing(privKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rawPwd := []byte(passphrase)
|
||||||
|
var decryptErr error
|
||||||
|
for _, key := range privKeyEntries.DecryptionKeys() {
|
||||||
|
priv := key.PrivateKey
|
||||||
|
if priv.Encrypted {
|
||||||
|
if err := priv.Decrypt(rawPwd); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if decryptErr = ek.Decrypt(priv, nil); decryptErr == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if decryptErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return getSessionSplit(ek)
|
||||||
|
}
|
||||||
|
|
||||||
|
//KeyPacketWithPublicKey ...
|
||||||
|
func KeyPacketWithPublicKey(sessionSplit *SessionSplit, publicKey string) ([]byte, error) {
|
||||||
|
pubkeyRaw, err := UnArmor(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return KeyPacketWithPublicKeyBin(sessionSplit, pubkeyRaw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyPacketWithPublicKeyBin ...
|
||||||
|
func KeyPacketWithPublicKeyBin(sessionSplit *SessionSplit, publicKey []byte) ([]byte, error) {
|
||||||
|
publicKeyReader := bytes.NewReader(publicKey)
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(publicKeyReader)
|
||||||
|
|
||||||
|
outbuf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
cf := cipherFunc(sessionSplit.Algo)
|
||||||
|
|
||||||
|
if len(pubKeyEntries) == 0 {
|
||||||
|
return nil, errors.New("cannot set key: key ring is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pub *packet.PublicKey
|
||||||
|
for _, e := range pubKeyEntries {
|
||||||
|
for _, subKey := range e.Subkeys {
|
||||||
|
if !subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications {
|
||||||
|
pub = subKey.PublicKey
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pub == nil && len(e.Identities) > 0 {
|
||||||
|
var i *openpgp.Identity
|
||||||
|
for _, i = range e.Identities {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptStorage || i.SelfSignature.FlagEncryptCommunications {
|
||||||
|
pub = e.PrimaryKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pub != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pub == nil {
|
||||||
|
return nil, errors.New("cannot set key: no public key available")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = packet.SerializeEncryptedKey(outbuf, pub, cf, sessionSplit.Session, nil); err != nil {
|
||||||
|
err = fmt.Errorf("pmapi: cannot set key: %v", err)
|
||||||
|
return nil, errors.New("cannot set key: key ring is empty")
|
||||||
|
}
|
||||||
|
return outbuf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetSessionFromSymmetricPacket ...
|
||||||
|
func GetSessionFromSymmetricPacket(keyPackage []byte, password string) (*SessionSplit, error) {
|
||||||
|
|
||||||
|
keyReader := bytes.NewReader(keyPackage)
|
||||||
|
packets := packet.NewReader(keyReader)
|
||||||
|
|
||||||
|
var symKeys []*packet.SymmetricKeyEncrypted
|
||||||
|
for {
|
||||||
|
|
||||||
|
var p packet.Packet
|
||||||
|
var err error
|
||||||
|
if p, err = packets.Next(); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch p := p.(type) {
|
||||||
|
case *packet.SymmetricKeyEncrypted:
|
||||||
|
symKeys = append(symKeys, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pwdRaw := []byte(password)
|
||||||
|
// Try the symmetric passphrase first
|
||||||
|
if len(symKeys) != 0 && pwdRaw != nil {
|
||||||
|
for _, s := range symKeys {
|
||||||
|
key, cipherFunc, err := s.Decrypt(pwdRaw)
|
||||||
|
if err == nil {
|
||||||
|
return &SessionSplit{
|
||||||
|
Session: key,
|
||||||
|
Algo: getAlog(cipherFunc),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("password incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SymmetricKeyPacketWithPassword ...
|
||||||
|
func SymmetricKeyPacketWithPassword(sessionSplit *SessionSplit, password string) ([]byte, error) {
|
||||||
|
outbuf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
cf := cipherFunc(sessionSplit.Algo)
|
||||||
|
|
||||||
|
if len(password) <= 0 {
|
||||||
|
return nil, errors.New("password can't be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
pwdRaw := []byte(password)
|
||||||
|
|
||||||
|
config := &packet.Config{
|
||||||
|
DefaultCipher: cf,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := packet.SerializeSymmetricKeyEncryptedReuseKey(outbuf, sessionSplit.Session, pwdRaw, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return outbuf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//symKeyAlgos ...
|
||||||
|
var symKeyAlgos = map[string]packet.CipherFunction{
|
||||||
|
"3des": packet.Cipher3DES,
|
||||||
|
"cast5": packet.CipherCAST5,
|
||||||
|
"aes128": packet.CipherAES128,
|
||||||
|
"aes192": packet.CipherAES192,
|
||||||
|
"aes256": packet.CipherAES256,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get this's cipher function.
|
||||||
|
func cipherFunc(algo string) packet.CipherFunction {
|
||||||
|
cf, ok := symKeyAlgos[algo]
|
||||||
|
if ok {
|
||||||
|
return cf
|
||||||
|
}
|
||||||
|
return packet.CipherAES256
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSessionSplit(ek *packet.EncryptedKey) (*SessionSplit, error) {
|
||||||
|
if ek == nil {
|
||||||
|
return nil, errors.New("can't decrypt key packet")
|
||||||
|
}
|
||||||
|
var algo string
|
||||||
|
for k, v := range symKeyAlgos {
|
||||||
|
if v == ek.CipherFunc {
|
||||||
|
algo = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if algo == "" {
|
||||||
|
algo = "aes256"
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SessionSplit{
|
||||||
|
Session: ek.Key,
|
||||||
|
Algo: algo,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAlog(cipher packet.CipherFunction) string {
|
||||||
|
var algo string
|
||||||
|
for k, v := range symKeyAlgos {
|
||||||
|
if v == cipher {
|
||||||
|
algo = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if algo == "" {
|
||||||
|
algo = "aes256"
|
||||||
|
}
|
||||||
|
|
||||||
|
return algo
|
||||||
|
}
|
||||||
|
|
||||||
|
//encode length based on 4.2.2. in the RFC
|
||||||
|
func encodedLength(length int) (b []byte) {
|
||||||
|
if length < 192 {
|
||||||
|
b = append(b, byte(length))
|
||||||
|
} else if length < 8384 {
|
||||||
|
length = length - 192
|
||||||
|
b = append(b, 192+byte(length>>8))
|
||||||
|
b = append(b, byte(length))
|
||||||
|
} else {
|
||||||
|
b = append(b, byte(255))
|
||||||
|
b = append(b, byte(length>>24))
|
||||||
|
b = append(b, byte(length>>16))
|
||||||
|
b = append(b, byte(length>>8))
|
||||||
|
b = append(b, byte(length))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//SeparateKeyAndData ...
|
||||||
|
func SeparateKeyAndData(encrypted string) (*EncryptedSplit, error) {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
encryptedRaw, err := UnArmor(encrypted)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedReader := bytes.NewReader(encryptedRaw)
|
||||||
|
|
||||||
|
//kr *KeyRing, r io.Reader) (key *SymmetricKey, symEncryptedData []byte,
|
||||||
|
packets := packet.NewReader(encryptedReader)
|
||||||
|
|
||||||
|
outSplt := &EncryptedSplit{}
|
||||||
|
|
||||||
|
// Save encrypted key and signature apart
|
||||||
|
var ek *packet.EncryptedKey
|
||||||
|
// var decryptErr error
|
||||||
|
for {
|
||||||
|
var p packet.Packet
|
||||||
|
if p, err = packets.Next(); err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch p := p.(type) {
|
||||||
|
case *packet.EncryptedKey:
|
||||||
|
// We got an encrypted key. Try to decrypt it with each available key
|
||||||
|
if ek != nil && ek.Key != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ek = p
|
||||||
|
break
|
||||||
|
case *packet.SymmetricallyEncrypted:
|
||||||
|
var packetContents []byte
|
||||||
|
if packetContents, err = ioutil.ReadAll(p.Contents); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedLength := encodedLength(len(packetContents) + 1)
|
||||||
|
var symEncryptedData []byte
|
||||||
|
symEncryptedData = append(symEncryptedData, byte(210))
|
||||||
|
symEncryptedData = append(symEncryptedData, encodedLength...)
|
||||||
|
symEncryptedData = append(symEncryptedData, byte(1))
|
||||||
|
symEncryptedData = append(symEncryptedData, packetContents...)
|
||||||
|
|
||||||
|
outSplt.DataPacket = symEncryptedData
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buff bytes.Buffer
|
||||||
|
ek.Serialize(&buff)
|
||||||
|
outSplt.KeyPacket = buff.Bytes()
|
||||||
|
|
||||||
|
return outSplt, err
|
||||||
|
}
|
||||||
322
sign_detached.go
Normal file
322
sign_detached.go
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
"golang.org/x/crypto/openpgp/clearsign"
|
||||||
|
"golang.org/x/crypto/openpgp/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ReadClearSignedMessage read clear message from a clearsign package
|
||||||
|
func ReadClearSignedMessage(signedMessage string) (string, error) {
|
||||||
|
modulusBlock, rest := clearsign.Decode([]byte(signedMessage))
|
||||||
|
if len(rest) != 0 {
|
||||||
|
return "", errors.New("pmapi: extra data after modulus")
|
||||||
|
}
|
||||||
|
return string(modulusBlock.Bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignTextDetached sign detached text type
|
||||||
|
func (o *OpenPGP) SignTextDetached(plainText string, privateKey string, passphrase string, trim bool) (string, error) {
|
||||||
|
//sign with 0x01 text
|
||||||
|
var signEntity *openpgp.Entity
|
||||||
|
|
||||||
|
signerReader := strings.NewReader(privateKey)
|
||||||
|
signerEntries, err := openpgp.ReadArmoredKeyRing(signerReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range signerEntries {
|
||||||
|
// Entity.PrivateKey must be a signing key
|
||||||
|
if e.PrivateKey != nil {
|
||||||
|
if e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt([]byte(passphrase))
|
||||||
|
}
|
||||||
|
if !e.PrivateKey.Encrypted {
|
||||||
|
signEntity = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signEntity == nil {
|
||||||
|
return "", errors.New("cannot sign message, singer key is not unlocked")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
|
||||||
|
att := strings.NewReader(plainText)
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
//SignText
|
||||||
|
if err = openpgp.ArmoredDetachSignText(&outBuf, signEntity, att, config); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignTextDetachedBinKey ...
|
||||||
|
func (o *OpenPGP) SignTextDetachedBinKey(plainText string, privateKey []byte, passphrase string, trim bool) (string, error) {
|
||||||
|
//sign with 0x01
|
||||||
|
var signEntity *openpgp.Entity
|
||||||
|
|
||||||
|
signerReader := bytes.NewReader(privateKey)
|
||||||
|
signerEntries, err := openpgp.ReadKeyRing(signerReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range signerEntries {
|
||||||
|
// Entity.PrivateKey must be a signing key
|
||||||
|
if e.PrivateKey != nil {
|
||||||
|
if e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt([]byte(passphrase))
|
||||||
|
}
|
||||||
|
if !e.PrivateKey.Encrypted {
|
||||||
|
signEntity = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signEntity == nil {
|
||||||
|
return "", errors.New("cannot sign message, singer key is not unlocked")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
|
||||||
|
att := strings.NewReader(plainText)
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
//sign text
|
||||||
|
if err = openpgp.ArmoredDetachSignText(&outBuf, signEntity, att, config); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignBinDetached sign bin data
|
||||||
|
func (o *OpenPGP) SignBinDetached(plainData []byte, privateKey string, passphrase string) (string, error) {
|
||||||
|
//sign with 0x00
|
||||||
|
var signEntity *openpgp.Entity
|
||||||
|
|
||||||
|
signerReader := strings.NewReader(privateKey)
|
||||||
|
signerEntries, err := openpgp.ReadArmoredKeyRing(signerReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range signerEntries {
|
||||||
|
// Entity.PrivateKey must be a signing key
|
||||||
|
if e.PrivateKey != nil {
|
||||||
|
if e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt([]byte(passphrase))
|
||||||
|
}
|
||||||
|
if !e.PrivateKey.Encrypted {
|
||||||
|
signEntity = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signEntity == nil {
|
||||||
|
return "", errors.New("cannot sign message, singer key is not unlocked")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
|
||||||
|
att := bytes.NewReader(plainData)
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
//sign bin
|
||||||
|
if err = openpgp.ArmoredDetachSign(&outBuf, signEntity, att, config); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignBinDetachedBinKey ...
|
||||||
|
func (o *OpenPGP) SignBinDetachedBinKey(plainData []byte, privateKey []byte, passphrase string) (string, error) {
|
||||||
|
//sign with 0x00
|
||||||
|
var signEntity *openpgp.Entity
|
||||||
|
|
||||||
|
signerReader := bytes.NewReader(privateKey)
|
||||||
|
signerEntries, err := openpgp.ReadKeyRing(signerReader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range signerEntries {
|
||||||
|
// Entity.PrivateKey must be a signing key
|
||||||
|
if e.PrivateKey != nil {
|
||||||
|
if e.PrivateKey.Encrypted {
|
||||||
|
e.PrivateKey.Decrypt([]byte(passphrase))
|
||||||
|
}
|
||||||
|
if !e.PrivateKey.Encrypted {
|
||||||
|
signEntity = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signEntity == nil {
|
||||||
|
return "", errors.New("cannot sign message, singer key is not unlocked")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &packet.Config{DefaultCipher: packet.CipherAES256}
|
||||||
|
|
||||||
|
att := bytes.NewReader(plainData)
|
||||||
|
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
//sign bin
|
||||||
|
if err = openpgp.ArmoredDetachSign(&outBuf, signEntity, att, config); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyTextSignDetached ...
|
||||||
|
func (o *OpenPGP) VerifyTextSignDetached(signature string, plainText string, publicKey string, verifyTime int64) (bool, error) {
|
||||||
|
|
||||||
|
pubKeyReader := strings.NewReader(publicKey)
|
||||||
|
|
||||||
|
pubKeyEntries, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureReader := strings.NewReader(signature)
|
||||||
|
|
||||||
|
origText := bytes.NewReader(bytes.NewBufferString(plainText).Bytes())
|
||||||
|
|
||||||
|
config := &packet.Config{}
|
||||||
|
if verifyTime > 0 {
|
||||||
|
tm := time.Unix(verifyTime, 0)
|
||||||
|
config.Time = func() time.Time {
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signer, err := openpgp.CheckArmoredDetachedSignature(pubKeyEntries, origText, signatureReader, config)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if signer == nil {
|
||||||
|
return false, errors.New("signer is empty")
|
||||||
|
}
|
||||||
|
// if signer.PrimaryKey.KeyId != signed.PrimaryKey.KeyId {
|
||||||
|
// // t.Errorf("wrong signer got:%x want:%x", signer.PrimaryKey.KeyId, 0)
|
||||||
|
// return false, errors.New("signer is nil")
|
||||||
|
// }
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyTextSignDetachedBinKey ...
|
||||||
|
func (o *OpenPGP) VerifyTextSignDetachedBinKey(signature string, plainText string, publicKey []byte, verifyTime int64) (bool, error) {
|
||||||
|
|
||||||
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
|
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureReader := strings.NewReader(signature)
|
||||||
|
|
||||||
|
origText := bytes.NewReader(bytes.NewBufferString(plainText).Bytes())
|
||||||
|
config := &packet.Config{}
|
||||||
|
if verifyTime > 0 {
|
||||||
|
tm := time.Unix(verifyTime, 0)
|
||||||
|
config.Time = func() time.Time {
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signer, err := openpgp.CheckArmoredDetachedSignature(pubKeyEntries, origText, signatureReader, config)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if signer == nil {
|
||||||
|
return false, errors.New("signer is empty")
|
||||||
|
}
|
||||||
|
// if signer.PrimaryKey.KeyId != signed.PrimaryKey.KeyId {
|
||||||
|
// // t.Errorf("wrong signer got:%x want:%x", signer.PrimaryKey.KeyId, 0)
|
||||||
|
// return false, errors.New("signer is nil")
|
||||||
|
// }
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyBinSignDetached ...
|
||||||
|
func (o *OpenPGP) VerifyBinSignDetached(signature string, plainData []byte, publicKey string, verifyTime int64) (bool, error) {
|
||||||
|
|
||||||
|
pubKeyReader := strings.NewReader(publicKey)
|
||||||
|
|
||||||
|
pubKeyEntries, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureReader := strings.NewReader(signature)
|
||||||
|
|
||||||
|
origText := bytes.NewReader(plainData)
|
||||||
|
config := &packet.Config{}
|
||||||
|
if verifyTime > 0 {
|
||||||
|
tm := time.Unix(verifyTime, 0)
|
||||||
|
config.Time = func() time.Time {
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signer, err := openpgp.CheckArmoredDetachedSignature(pubKeyEntries, origText, signatureReader, config)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if signer == nil {
|
||||||
|
return false, errors.New("signer is empty")
|
||||||
|
}
|
||||||
|
// if signer.PrimaryKey.KeyId != signed.PrimaryKey.KeyId {
|
||||||
|
// // t.Errorf("wrong signer got:%x want:%x", signer.PrimaryKey.KeyId, 0)
|
||||||
|
// return false, errors.New("signer is nil")
|
||||||
|
// }
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyBinSignDetachedBinKey ...
|
||||||
|
func (o *OpenPGP) VerifyBinSignDetachedBinKey(signature string, plainData []byte, publicKey []byte, verifyTime int64) (bool, error) {
|
||||||
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
|
|
||||||
|
pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureReader := strings.NewReader(signature)
|
||||||
|
|
||||||
|
origText := bytes.NewReader(plainData)
|
||||||
|
|
||||||
|
config := &packet.Config{}
|
||||||
|
if verifyTime > 0 {
|
||||||
|
tm := time.Unix(verifyTime, 0)
|
||||||
|
config.Time = func() time.Time {
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signer, err := openpgp.CheckArmoredDetachedSignature(pubKeyEntries, origText, signatureReader, config)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if signer == nil {
|
||||||
|
return false, errors.New("signer is empty")
|
||||||
|
}
|
||||||
|
// if signer.PrimaryKey.KeyId != signed.PrimaryKey.KeyId {
|
||||||
|
// // t.Errorf("wrong signer got:%x want:%x", signer.PrimaryKey.KeyId, 0)
|
||||||
|
// return false, errors.New("signer is nil")
|
||||||
|
// }
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
25
time.go
Normal file
25
time.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpdateTime update cached time
|
||||||
|
func (o *OpenPGP) UpdateTime(newTime int64) {
|
||||||
|
o.lastestServerTime = newTime
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetTime get latest cached time
|
||||||
|
func (o *OpenPGP) GetTime() int64 {
|
||||||
|
return o.lastestServerTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OpenPGP) getNow() time.Time {
|
||||||
|
|
||||||
|
if o.lastestServerTime > 0 {
|
||||||
|
tm := time.Unix(o.lastestServerTime, 0)
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
6
version.go
Normal file
6
version.go
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package pm
|
||||||
|
|
||||||
|
// Version get current lib version
|
||||||
|
func Version() string {
|
||||||
|
return "ddacebe0"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue