Add build script and fix helper for mobile (#32)

* update build and fix helper for mobile

* Update readme, changelog and script cleanup

Co-authored-by: wussler <aron@wussler.it>
This commit is contained in:
Yanfeng Zhang 2020-01-06 04:21:44 -08:00 committed by wussler
parent 54f45d0471
commit 5c496d0505
8 changed files with 242 additions and 90 deletions

View file

@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.0.0] - 2019-12-?? ## [2.0.0] - 2020-01-06
Since the open-sourcing of the library in May the API has been updated, listening to internal and Since the open-sourcing of the library in May the API has been updated, listening to internal and
external feedback, in order to have a flexible library, that can be used in a simple settings, external feedback, in order to have a flexible library, that can be used in a simple settings,
with batteries included, or by more advanced users that might want to interact directly with with batteries included, or by more advanced users that might want to interact directly with

View file

@ -72,7 +72,28 @@ https://godoc.org/gopkg.in/ProtonMail/gopenpgp.v2/crypto
In this document examples are provided and the proper use of (almost) all functions is tested. In this document examples are provided and the proper use of (almost) all functions is tested.
## Using with Go Mobile ## Using with Go Mobile
The use with gomobile is still to be documented This library can be compiled with [Gomobile](https://github.com/golang/go/wiki/Mobile) too.
First ensure you have a working installation of gomobile:
```bash
gomobile version
```
In case this fails, install it with:
```bash
go get -u golang.org/x/mobile/cmd/gomobile
```
Then ensure your path env var has gomobile's binary, and it is properly init-ed:
```bash
export PATH="$PATH:$GOPATH/bin"
gomobile init
```
Then you must ensure that the Android or iOS frameworks are installed and the respective env vars set.
Finally, build the application
```bash
sh build.sh
```
This script will build for both android and iOS at the same time,
to filter one out you can comment out the line in the corresponding section.
## Examples ## Examples

101
build.sh Executable file
View file

@ -0,0 +1,101 @@
#!/bin/bash
PACKAGE_PATH="github.com/ProtonMail/gopenpgp"
cd "${GOPATH}"/src/${PACKAGE_PATH} || exit
if ! [ -L "v2" ]; then
ln -s . v2
fi
printf "\e[0;32mStart installing vendor \033[0m\n\n"
export GO111MODULE=on
go mod vendor
printf "\e[0;32mDone \033[0m\n\n"
OUTPUT_PATH="dist"
ANDROID_OUT=${OUTPUT_PATH}/"Android"
ANDROID_OUT_FILE_NAME="gopenpgp"
ANDROID_OUT_FILE=${ANDROID_OUT}/${ANDROID_OUT_FILE_NAME}.aar
ANDROID_JAVA_PAG="com.proton.${ANDROID_OUT_FILE_NAME}"
IOS_OUT=${OUTPUT_PATH}/"iOS"
IOS_OUT_FILE_NAME="Crypto"
IOS_OUT_FILE=${IOS_OUT}/${IOS_OUT_FILE_NAME}.framework
mkdir -p $ANDROID_OUT
mkdir -p $IOS_OUT
install()
{
INSTALL_NAME=$1
FROM_PATH=$2
INSTALL_PATH=$3
if [[ -z "${INSTALL_PATH}" ]]; then
printf "\e[0;32m ${INSTALL_NAME} project path is undefined! ignore this !\033[0m\n";
else
printf "\n\e[0;32mDo you wise to install the library into ${INSTALL_NAME} project \033[0m\n"
printf "\e[0;37m${INSTALL_NAME} Project Path: \033[0m"
printf "\e[0;37m${INSTALL_PATH} \033[0m"
printf "\n"
while true; do
read -p "[Yy] or [Nn]:" yn
case $yn in
[Yy]* )
printf "\e[0;32m Installing .... \033[0m\n";
cp -rf ${FROM_PATH} ${INSTALL_PATH}/
printf "\n\e[0;32mInstalled \033[0m\n\n"
break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
fi
}
# import function, add internal package in the build
import()
{
PACKAGES=" ${PACKAGES} ${PACKAGE_PATH}/v2/$1"
}
external()
{
PACKAGES="${PACKAGES} $1"
}
######## MARK -- Main
#flags
DFLAGS="-s -w"
PACKAGES=""
#add internal package
## crypto must be the first one, and the framework name better same with the first package name
import crypto
import armor
import constants
import models
import subtle
import helper
## add external package
if [ "$1" != '' ]; then
external $1
fi
printf "PACKAGES: ${PACKAGES}\n"
## start building
printf "\e[0;32mStart Building iOS framework .. Location: ${IOS_OUT} \033[0m\n\n"
gomobile bind -target ios -o ${IOS_OUT_FILE} -ldflags="${DFLAGS}" ${PACKAGES}
# install iOS ${IOS_OUT_FILE} ${IOS_PROJECT_PATH}
printf "\e[0;32mStart Building Android lib .. Location: ${ANDROID_OUT} \033[0m\n\n"
gomobile bind -target android -javapkg ${ANDROID_JAVA_PAG} -o ${ANDROID_OUT_FILE} -ldflags="${DFLAGS}" ${PACKAGES}
# install Android ${ANDROID_OUT} ${ANDROID_PROJECT_PATH}
printf "\e[0;32mInstalling frameworks. \033[0m\n\n"
printf "\e[0;32mAll Done. \033[0m\n\n"

View file

@ -184,50 +184,6 @@ func DecryptVerifyMessageArmored(
return message.GetString(), nil return message.GetString(), nil
} }
// EncryptSignAttachment encrypts an attachment using a detached signature, given a publicKey, a privateKey
// and its passphrase, the filename, and the unencrypted file data.
// Returns keypacket, dataPacket and unarmored (!) signature separate.
func EncryptSignAttachment(
publicKey, privateKey string, passphrase []byte, fileName string, plainData []byte,
) (keyPacket, dataPacket, signature []byte, err error) {
var publicKeyObj, privateKeyObj, unlockedKeyObj *crypto.Key
var publicKeyRing, privateKeyRing *crypto.KeyRing
var packets *crypto.PGPSplitMessage
var signatureObj *crypto.PGPSignature
var binMessage = crypto.NewPlainMessage(plainData)
if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil {
return nil, nil, nil, err
}
if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil {
return nil, nil, nil, err
}
if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil {
return nil, nil, nil, err
}
if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil {
return nil, nil, nil, err
}
if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
return nil, nil, nil, err
}
if packets, err = publicKeyRing.EncryptAttachment(binMessage, fileName); err != nil {
return nil, nil, nil, err
}
if signatureObj, err = privateKeyRing.SignDetached(binMessage); err != nil {
return nil, nil, nil, err
}
return packets.GetBinaryKeyPacket(), packets.GetBinaryDataPacket(), signatureObj.GetBinary(), nil
}
// DecryptVerifyAttachment decrypts and verifies an attachment split into the keyPacket, dataPacket // DecryptVerifyAttachment decrypts and verifies an attachment split into the keyPacket, dataPacket
// and an armored (!) signature, given a publicKey, and a privateKey with its passphrase. // and an armored (!) signature, given a publicKey, and a privateKey with its passphrase.
// Returns the plain data or an error on signature verification failure. // Returns the plain data or an error on signature verification failure.

View file

@ -1,43 +0,0 @@
package helper
import (
"github.com/ProtonMail/gopenpgp/v2/crypto"
)
// ExplicitVerifyMessage contains explicitly the signature verification error, for gomobile users
type ExplicitVerifyMessage struct {
Message *crypto.PlainMessage
SignatureVerificationError *crypto.SignatureVerificationError
}
// DecryptExplicitVerify decrypts an armored PGP message given a private key and its passphrase
// and verifies the embedded signature.
// Returns the plain data or an error on signature verification failure.
func DecryptExplicitVerify(
pgpMessage *crypto.PGPMessage,
privateKeyRing, publicKeyRing *crypto.KeyRing,
verifyTime int64,
) (*ExplicitVerifyMessage, error) {
var explicitVerify *ExplicitVerifyMessage
message, err := privateKeyRing.Decrypt(pgpMessage, publicKeyRing, verifyTime)
if err != nil {
castedErr, isType := err.(crypto.SignatureVerificationError)
if !isType {
return nil, err
}
explicitVerify = &ExplicitVerifyMessage{
Message: message,
SignatureVerificationError: &castedErr,
}
} else {
explicitVerify = &ExplicitVerifyMessage{
Message: message,
SignatureVerificationError: nil,
}
}
return explicitVerify, nil
}

67
helper/mobile.go Normal file
View file

@ -0,0 +1,67 @@
package helper
import (
"github.com/ProtonMail/gopenpgp/v2/crypto"
)
type ExplicitVerifyMessage struct {
Message *crypto.PlainMessage
SignatureVerificationError *crypto.SignatureVerificationError
}
// DecryptVerifyMessageArmored decrypts an armored PGP message given a private key and its passphrase
// and verifies the embedded signature.
// Returns the plain data or an error on signature verification failure.
func DecryptExplicitVerify(
pgpMessage *crypto.PGPMessage,
privateKeyRing, publicKeyRing *crypto.KeyRing,
verifyTime int64,
) (*ExplicitVerifyMessage, error) {
var explicitVerify *ExplicitVerifyMessage
message, err := privateKeyRing.Decrypt(pgpMessage, publicKeyRing, verifyTime)
if err != nil {
castedErr, isType := err.(crypto.SignatureVerificationError)
if !isType {
return nil, err
}
explicitVerify = &ExplicitVerifyMessage{
Message: message,
SignatureVerificationError: &castedErr,
}
} else {
explicitVerify = &ExplicitVerifyMessage{
Message: message,
SignatureVerificationError: nil,
}
}
return explicitVerify, nil
}
// DecryptAttachment takes a keypacket and datpacket
// and returns a decrypted PlainMessage
// Specifically designed for attachments rather than text messages.
func DecryptAttachment(keyPacket []byte, dataPacket []byte, keyRing *crypto.KeyRing) (*crypto.PlainMessage, error) {
splitMessage := crypto.NewPGPSplitMessage(keyPacket, dataPacket)
decrypted, err := keyRing.DecryptAttachment(splitMessage)
if err != nil {
return nil, err
}
return decrypted, nil
}
// EncryptAttachment encrypts a file given a plainData and a fileName.
// Returns a PGPSplitMessage containing a session key packet and symmetrically encrypted data.
// Specifically designed for attachments rather than text messages.
func EncryptAttachment(plainData []byte, fileName string, keyRing *crypto.KeyRing) (*crypto.PGPSplitMessage, error) {
plainMessage := crypto.NewPlainMessage(plainData)
decrypted, err := keyRing.EncryptAttachment(plainMessage, fileName)
if err != nil {
return nil, err
}
return decrypted, nil
}

View file

@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestIOSSignedMessageDecryption(t *testing.T) { func TestMobileSignedMessageDecryption(t *testing.T) {
privateKey, _ := crypto.NewKeyFromArmored(readTestFile("keyring_privateKey", false)) privateKey, _ := crypto.NewKeyFromArmored(readTestFile("keyring_privateKey", false))
// Password defined in base_test // Password defined in base_test
privateKey, err := privateKey.Unlock(testMailboxPassword) privateKey, err := privateKey.Unlock(testMailboxPassword)

50
helper/sign_attachment.go Normal file
View file

@ -0,0 +1,50 @@
// +build !ios
// +build !android
package helper
import "github.com/ProtonMail/gopenpgp/v2/crypto"
// EncryptSignAttachment encrypts an attachment using a detached signature, given a publicKey, a privateKey
// and its passphrase, the filename, and the unencrypted file data.
// Returns keypacket, dataPacket and unarmored (!) signature separate.
func EncryptSignAttachment(
publicKey, privateKey string, passphrase []byte, fileName string, plainData []byte,
) (keyPacket, dataPacket, signature []byte, err error) {
var publicKeyObj, privateKeyObj, unlockedKeyObj *crypto.Key
var publicKeyRing, privateKeyRing *crypto.KeyRing
var packets *crypto.PGPSplitMessage
var signatureObj *crypto.PGPSignature
var binMessage = crypto.NewPlainMessage(plainData)
if publicKeyObj, err = crypto.NewKeyFromArmored(publicKey); err != nil {
return nil, nil, nil, err
}
if publicKeyRing, err = crypto.NewKeyRing(publicKeyObj); err != nil {
return nil, nil, nil, err
}
if privateKeyObj, err = crypto.NewKeyFromArmored(privateKey); err != nil {
return nil, nil, nil, err
}
if unlockedKeyObj, err = privateKeyObj.Unlock(passphrase); err != nil {
return nil, nil, nil, err
}
if privateKeyRing, err = crypto.NewKeyRing(unlockedKeyObj); err != nil {
return nil, nil, nil, err
}
if packets, err = publicKeyRing.EncryptAttachment(binMessage, fileName); err != nil {
return nil, nil, nil, err
}
if signatureObj, err = privateKeyRing.SignDetached(binMessage); err != nil {
return nil, nil, nil, err
}
return packets.GetBinaryKeyPacket(), packets.GetBinaryDataPacket(), signatureObj.GetBinary(), nil
}