diff --git a/.gitignore b/.gitignore index 99b3bbb..bea5308 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store bin +pkg vendor -.vscode \ No newline at end of file +.vscode diff --git a/armor/armor.go b/armor/armor.go deleted file mode 100644 index 678f0dd..0000000 --- a/armor/armor.go +++ /dev/null @@ -1,129 +0,0 @@ -package armor - -import ( - "bytes" - "errors" - "gitlab.com/ProtonMail/go-pm-crypto/internal" - "gitlab.com/ProtonMail/go-pm-crypto/models" - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/clearsign" - "golang.org/x/crypto/openpgp/packet" - "io" - "io/ioutil" -) - -// ArmorKey make bytes input key to armor format -func ArmorKey(input []byte) (string, error) { - return ArmorWithType(input, PUBLIC_KEY_HEADER) -} - -// 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, internal.ArmorHeaders) - 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 := internal.Unarmor(input) - if err != nil { - return nil, err - } - return ioutil.ReadAll(b.Body) -} - -//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 -} - -//SeparateKeyAndData ... -func SplitArmor(encrypted string) (*models.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) - - outSplit := &models.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...) - - outSplit.DataPacket = symEncryptedData - break - - } - } - - var buf bytes.Buffer - ek.Serialize(&buf) - outSplit.KeyPacket = buf.Bytes() - - return outSplit, err -} - -//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 -} diff --git a/build.sh b/build.sh index ae2de9f..1b4c8b5 100755 --- a/build.sh +++ b/build.sh @@ -7,18 +7,23 @@ ANDROID_OUT=${OUTPUT_PATH}/"Android" IOS_OUT=${OUTPUT_PATH}/"iOS" mkdir -p $ANDROID_OUT mkdir -p $IOS_OUT + +ln -s . vendor/src + # 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}/pmcrypto.framework proton/pmcrypto/crypto proton/pmcrypto/armor proton/pmcrypto/constants proton/pmcrypto/key proton/pmcrypto/models +GOPATH="$SCRIPT_LOCATION:$SCRIPT_LOCATION/vendor:$GOPATH" gomobile bind -target ios -o ${IOS_OUT}/Crypto.framework -ldflags="-s -w" gitlab.com/ProtonMail/go-pm-crypto/crypto gitlab.com/ProtonMail/go-pm-crypto/armor gitlab.com/ProtonMail/go-pm-crypto/constants gitlab.com/ProtonMail/go-pm-crypto/key gitlab.com/ProtonMail/go-pm-crypto/models printf "\e[0;32mStart Building Android lib .. Location: ${ANDROID_OUT} \033[0m\n\n" -gomobile bind -target android -javapkg com.proton.pmcrypto -o ${ANDROID_OUT}/pmcrypto.aar proton/pmcrypto/crypto proton/pmcrypto/armor proton/pmcrypto/constants proton/pmcrypto/key proton/pmcrypto/models +GOPATH="$SCRIPT_LOCATION:$SCRIPT_LOCATION/vendor:$GOPATH" gomobile bind -target android -javapkg com.proton.pmcrypto -o ${ANDROID_OUT}/pmcrypto.aar -ldflags="-s -w" gitlab.com/ProtonMail/go-pm-crypto/crypto gitlab.com/ProtonMail/go-pm-crypto/armor gitlab.com/ProtonMail/go-pm-crypto/constants gitlab.com/ProtonMail/go-pm-crypto/key gitlab.com/ProtonMail/go-pm-crypto/models printf "\e[0;32mInstalling frameworks. \033[0m\n\n" +unlink vendor/src + printf "\e[0;32mAll Done. \033[0m\n\n" diff --git a/debug_build.sh b/debug_build.sh new file mode 100755 index 0000000..0d4eead --- /dev/null +++ b/debug_build.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +SCRIPT_LOCATION=$(cd $(dirname $0);echo $PWD) + +BUILD_PATH="build" +OUTPUT_PATH="dist" +ANDROID_OUT=${OUTPUT_PATH}/"Android" +IOS_OUT=${OUTPUT_PATH}/"iOS" +rm -rf $BUILD_PATH +mkdir -p $BUILD_PATH +mkdir -p $ANDROID_OUT +mkdir -p $IOS_OUT + +ln -s . vendor/src + +# CHECK="${1-0}" +# if [ ${CHECK} -eq "1" ]; then +printf "\e[0;32mStart Building iOS framework .. Location: ${IOS_OUT} \033[0m\n\n" + +GOPATH="$SCRIPT_LOCATION:$SCRIPT_LOCATION/vendor:$GOPATH" gomobile bind -target ios -o ${IOS_OUT}/pmcrypto.framework gitlab.com/ProtonMail/go-pm-crypto/crypto gitlab.com/ProtonMail/go-pm-crypto/armor gitlab.com/ProtonMail/go-pm-crypto/constants gitlab.com/ProtonMail/go-pm-crypto/key gitlab.com/ProtonMail/go-pm-crypto/models + +printf "\e[0;32mStart Building Android lib .. Location: ${ANDROID_OUT} \033[0m\n\n" + +GOPATH="$SCRIPT_LOCATION:$SCRIPT_LOCATION/vendor:$GOPATH" gomobile bind -target android -javapkg com.proton.pmcrypto -o ${OUTPUT_PATH}/pmcrypto.aar gitlab.com/ProtonMail/go-pm-crypto/crypto gitlab.com/ProtonMail/go-pm-crypto/armor gitlab.com/ProtonMail/go-pm-crypto/constants gitlab.com/ProtonMail/go-pm-crypto/key gitlab.com/ProtonMail/go-pm-crypto/models + +printf "\e[0;32mInstalling frameworks. \033[0m\n\n" + +unlink vendor/src + +printf "\e[0;32mAll Done. \033[0m\n\n" + + diff --git a/dist/Android/pmcrypto-sources.jar b/dist/Android/pmcrypto-sources.jar index 1787558..2b760a5 100644 Binary files a/dist/Android/pmcrypto-sources.jar and b/dist/Android/pmcrypto-sources.jar differ diff --git a/dist/Android/pmcrypto.aar b/dist/Android/pmcrypto.aar index f4d33e2..9a5c2bf 100644 Binary files a/dist/Android/pmcrypto.aar and b/dist/Android/pmcrypto.aar differ diff --git a/dist/iOS/Crypto.framework.zip b/dist/iOS/Crypto.framework.zip new file mode 100644 index 0000000..932e885 Binary files /dev/null and b/dist/iOS/Crypto.framework.zip differ diff --git a/dist/iOS/Crypto.framework/Crypto b/dist/iOS/Crypto.framework/Crypto new file mode 120000 index 0000000..2e04b9d --- /dev/null +++ b/dist/iOS/Crypto.framework/Crypto @@ -0,0 +1 @@ +Versions/Current/Crypto \ No newline at end of file diff --git a/dist/iOS/Crypto.framework/Headers b/dist/iOS/Crypto.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/dist/iOS/Crypto.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/dist/iOS/Crypto.framework/Modules b/dist/iOS/Crypto.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/dist/iOS/Crypto.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/dist/iOS/Crypto.framework/Resources b/dist/iOS/Crypto.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/dist/iOS/Crypto.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/dist/iOS/Crypto.framework/Versions/A/Crypto b/dist/iOS/Crypto.framework/Versions/A/Crypto new file mode 100644 index 0000000..fa811fe Binary files /dev/null and b/dist/iOS/Crypto.framework/Versions/A/Crypto differ diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/Armor.objc.h b/dist/iOS/Crypto.framework/Versions/A/Headers/Armor.objc.h new file mode 100644 index 0000000..1b37df1 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/Armor.objc.h @@ -0,0 +1,42 @@ +// Objective-C API for talking to gitlab.com/ProtonMail/go-pm-crypto/armor Go package. +// gobind -lang=objc gitlab.com/ProtonMail/go-pm-crypto/armor +// +// File is generated by gobind. Do not edit. + +#ifndef __Armor_H__ +#define __Armor_H__ + +@import Foundation; +#include "Universe.objc.h" + +#include "Models.objc.h" + +FOUNDATION_EXPORT NSString* const ArmorARMOR_HEADER_COMMENT; +FOUNDATION_EXPORT NSString* const ArmorARMOR_HEADER_VERSION; +FOUNDATION_EXPORT NSString* const ArmorMESSAGE_HEADER; +FOUNDATION_EXPORT NSString* const ArmorPRIVATE_KEY_HEADER; +FOUNDATION_EXPORT NSString* const ArmorPUBLIC_KEY_HEADER; + +/** + * ArmorKey make bytes input key to armor format + */ +FOUNDATION_EXPORT NSString* ArmorArmorKey(NSData* input, NSError** error); + +/** + * ArmorWithType make bytes input to armor format + */ +FOUNDATION_EXPORT NSString* ArmorArmorWithType(NSData* input, NSString* armorType, NSError** error); + +/** + * ReadClearSignedMessage read clear message from a clearsign package + */ +FOUNDATION_EXPORT NSString* ArmorReadClearSignedMessage(NSString* signedMessage, NSError** error); + +FOUNDATION_EXPORT ModelsEncryptedSplit* ArmorSplitArmor(NSString* encrypted, NSError** error); + +/** + * Unarmor an armored key to bytes key + */ +FOUNDATION_EXPORT NSData* ArmorUnarmor(NSString* input, NSError** error); + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/Constants.objc.h b/dist/iOS/Crypto.framework/Versions/A/Headers/Constants.objc.h new file mode 100644 index 0000000..b32fbf4 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/Constants.objc.h @@ -0,0 +1,15 @@ +// Objective-C API for talking to gitlab.com/ProtonMail/go-pm-crypto/constants Go package. +// gobind -lang=objc gitlab.com/ProtonMail/go-pm-crypto/constants +// +// File is generated by gobind. Do not edit. + +#ifndef __Constants_H__ +#define __Constants_H__ + +@import Foundation; +#include "Universe.objc.h" + + +FOUNDATION_EXPORT NSString* const ConstantsVERSION; + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/Crypto.h b/dist/iOS/Crypto.framework/Versions/A/Headers/Crypto.h new file mode 100644 index 0000000..ee54a51 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/Crypto.h @@ -0,0 +1,21 @@ + +// Objective-C API for talking to the following Go packages +// +// gitlab.com/ProtonMail/go-pm-crypto/crypto +// gitlab.com/ProtonMail/go-pm-crypto/armor +// gitlab.com/ProtonMail/go-pm-crypto/constants +// gitlab.com/ProtonMail/go-pm-crypto/key +// gitlab.com/ProtonMail/go-pm-crypto/models +// +// File is generated by gomobile bind. Do not edit. +#ifndef __Crypto_FRAMEWORK_H__ +#define __Crypto_FRAMEWORK_H__ + +#include "Crypto.objc.h" +#include "Armor.objc.h" +#include "Constants.objc.h" +#include "Key.objc.h" +#include "Models.objc.h" +#include "universe.objc.h" + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/Crypto.objc.h b/dist/iOS/Crypto.framework/Versions/A/Headers/Crypto.objc.h new file mode 100644 index 0000000..b3b66d0 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/Crypto.objc.h @@ -0,0 +1,180 @@ +// Objective-C API for talking to gitlab.com/ProtonMail/go-pm-crypto/crypto Go package. +// gobind -lang=objc gitlab.com/ProtonMail/go-pm-crypto/crypto +// +// File is generated by gobind. Do not edit. + +#ifndef __Crypto_H__ +#define __Crypto_H__ + +@import Foundation; +#include "Universe.objc.h" + +#include "Armor.objc.h" +#include "Models.objc.h" + +@class CryptoAttachmentProcessor; +@class CryptoPmCrypto; +@class CryptoSignatureCollector; +@protocol CryptoMIMECallbacks; +@class CryptoMIMECallbacks; + +@protocol CryptoMIMECallbacks +- (void)onAttachment:(NSString*)headers data:(NSData*)data; +- (void)onBody:(NSString*)body mimetype:(NSString*)mimetype; +- (void)onEncryptedHeaders:(NSString*)headers; +- (void)onError:(NSError*)err; +- (void)onVerified:(long)verified; +@end + +/** + * EncryptedSplit when encrypt attachment + */ +@interface CryptoAttachmentProcessor : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +- (ModelsEncryptedSplit*)finish:(NSError**)error; +- (void)process:(NSData*)plainData; +@end + +/** + * PmCrypto structure to manage multiple address keys and user keys +Called PGP crypto because it cannot have the same name as the package by gomobile's ridiculous rules. + */ +@interface CryptoPmCrypto : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +- (NSString*)checkKey:(NSString*)pubKey error:(NSError**)error; +- (NSData*)decryptAttachment:(NSData*)keyPacket dataPacket:(NSData*)dataPacket privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +- (NSData*)decryptAttachmentBinKey:(NSData*)keyPacket dataPacket:(NSData*)dataPacket privateKeys:(NSData*)privateKeys passphrase:(NSString*)passphrase error:(NSError**)error; +- (NSData*)decryptAttachmentWithPassword:(NSData*)keyPacket dataPacket:(NSData*)dataPacket password:(NSString*)password error:(NSError**)error; +- (void)decryptMIMEMessage:(NSString*)encryptedText verifierKey:(NSData*)verifierKey privateKeys:(NSData*)privateKeys passphrase:(NSString*)passphrase callbacks:(id)callbacks verifyTime:(int64_t)verifyTime; +- (NSString*)decryptMessage:(NSString*)encryptedText privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +- (NSString*)decryptMessageBinKey:(NSString*)encryptedText privateKey:(NSData*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +- (ModelsDecryptSignedVerify*)decryptMessageVerify:(NSString*)encryptedText verifierKey:(NSString*)verifierKey privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase verifyTime:(int64_t)verifyTime error:(NSError**)error; +- (ModelsDecryptSignedVerify*)decryptMessageVerifyBinKey:(NSString*)encryptedText verifierKey:(NSData*)verifierKey privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase verifyTime:(int64_t)verifyTime error:(NSError**)error; +- (ModelsDecryptSignedVerify*)decryptMessageVerifyBinKeyPrivBinKeys:(NSString*)encryptedText verifierKey:(NSData*)verifierKey privateKeys:(NSData*)privateKeys passphrase:(NSString*)passphrase verifyTime:(int64_t)verifyTime error:(NSError**)error; +- (ModelsDecryptSignedVerify*)decryptMessageVerifyPrivBinKeys:(NSString*)encryptedText verifierKey:(NSString*)verifierKey privateKeys:(NSData*)privateKeys passphrase:(NSString*)passphrase verifyTime:(int64_t)verifyTime error:(NSError**)error; +- (NSString*)decryptMessageWithPassword:(NSString*)encrypted password:(NSString*)password error:(NSError**)error; +- (ModelsEncryptedSplit*)encryptAttachment:(NSData*)plainData fileName:(NSString*)fileName publicKey:(NSString*)publicKey error:(NSError**)error; +- (CryptoAttachmentProcessor*)encryptAttachmentLowMemory:(long)estimatedSize fileName:(NSString*)fileName publicKey:(NSString*)publicKey error:(NSError**)error; +- (NSString*)encryptAttachmentWithPassword:(NSData*)plainData password:(NSString*)password error:(NSError**)error; +- (NSString*)encryptMessage:(NSString*)plainText publicKey:(NSString*)publicKey privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase trim:(BOOL)trim error:(NSError**)error; +- (NSString*)encryptMessageBinKey:(NSString*)plainText publicKey:(NSData*)publicKey privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase trim:(BOOL)trim error:(NSError**)error; +- (NSString*)encryptMessageWithPassword:(NSString*)plainText password:(NSString*)password error:(NSError**)error; +- (NSString*)generateKey:(NSString*)userName domain:(NSString*)domain passphrase:(NSString*)passphrase keyType:(NSString*)keyType bits:(long)bits error:(NSError**)error; +- (NSString*)generateRSAKeyWithPrimes:(NSString*)userName domain:(NSString*)domain passphrase:(NSString*)passphrase bits:(long)bits primeone:(NSData*)primeone primetwo:(NSData*)primetwo primethree:(NSData*)primethree primefour:(NSData*)primefour error:(NSError**)error; +/** + * GetSessionFromKeyPacket get session key no encoding in and out + */ +- (ModelsSessionSplit*)getSessionFromKeyPacket:(NSData*)keyPackage privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +/** + * GetSessionFromKeyPacketBinkeys get session key no encoding in and out + */ +- (ModelsSessionSplit*)getSessionFromKeyPacketBinkeys:(NSData*)keyPackage privateKey:(NSData*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +/** + * GetSessionFromSymmetricPacket ... + */ +- (ModelsSessionSplit*)getSessionFromSymmetricPacket:(NSData*)keyPackage password:(NSString*)password error:(NSError**)error; +/** + * GetTime get latest cached time + */ +- (int64_t)getTime; +- (BOOL)isKeyExpired:(NSString*)publicKey ret0_:(BOOL*)ret0_ error:(NSError**)error; +- (BOOL)isKeyExpiredBin:(NSData*)publicKey ret0_:(BOOL*)ret0_ error:(NSError**)error; +/** + * KeyPacketWithPublicKey ... + */ +- (NSData*)keyPacketWithPublicKey:(ModelsSessionSplit*)sessionSplit publicKey:(NSString*)publicKey error:(NSError**)error; +/** + * KeyPacketWithPublicKeyBin ... + */ +- (NSData*)keyPacketWithPublicKeyBin:(ModelsSessionSplit*)sessionSplit publicKey:(NSData*)publicKey error:(NSError**)error; +/** + * RandomToken ... + */ +- (NSData*)randomToken:(NSError**)error; +/** + * RandomTokenWith ... + */ +- (NSData*)randomTokenWith:(long)size error:(NSError**)error; +/** + * SignBinDetached sign bin data + */ +- (NSString*)signBinDetached:(NSData*)plainData privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +/** + * SignBinDetachedBinKey ... + */ +- (NSString*)signBinDetachedBinKey:(NSData*)plainData privateKey:(NSData*)privateKey passphrase:(NSString*)passphrase error:(NSError**)error; +/** + * SignTextDetached sign detached text type + */ +- (NSString*)signTextDetached:(NSString*)plainText privateKey:(NSString*)privateKey passphrase:(NSString*)passphrase trim:(BOOL)trim error:(NSError**)error; +/** + * SignTextDetachedBinKey ... + */ +- (NSString*)signTextDetachedBinKey:(NSString*)plainText privateKey:(NSData*)privateKey passphrase:(NSString*)passphrase trim:(BOOL)trim error:(NSError**)error; +/** + * SymmetricKeyPacketWithPassword ... + */ +- (NSData*)symmetricKeyPacketWithPassword:(ModelsSessionSplit*)sessionSplit password:(NSString*)password error:(NSError**)error; +- (NSString*)updatePrivateKeyPassphrase:(NSString*)privateKey oldPassphrase:(NSString*)oldPassphrase newPassphrase:(NSString*)newPassphrase error:(NSError**)error; +/** + * UpdateTime update cached time + */ +- (void)updateTime:(int64_t)newTime; +/** + * VerifyBinSignDetached ... + */ +- (BOOL)verifyBinSignDetached:(NSString*)signature plainData:(NSData*)plainData publicKey:(NSString*)publicKey verifyTime:(int64_t)verifyTime ret0_:(BOOL*)ret0_ error:(NSError**)error; +/** + * VerifyBinSignDetachedBinKey ... + */ +- (BOOL)verifyBinSignDetachedBinKey:(NSString*)signature plainData:(NSData*)plainData publicKey:(NSData*)publicKey verifyTime:(int64_t)verifyTime ret0_:(BOOL*)ret0_ error:(NSError**)error; +/** + * VerifyTextSignDetached ... + */ +- (BOOL)verifyTextSignDetached:(NSString*)signature plainText:(NSString*)plainText publicKey:(NSString*)publicKey verifyTime:(int64_t)verifyTime ret0_:(BOOL*)ret0_ error:(NSError**)error; +/** + * VerifyTextSignDetachedBinKey ... + */ +- (BOOL)verifyTextSignDetachedBinKey:(NSString*)signature plainText:(NSString*)plainText publicKey:(NSData*)publicKey verifyTime:(int64_t)verifyTime ret0_:(BOOL*)ret0_ error:(NSError**)error; +@end + +@interface CryptoSignatureCollector : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +// skipped method SignatureCollector.Accept with unsupported parameter or return types + +- (NSString*)getSignature; +@end + +@class CryptoMIMECallbacks; + +/** + * define call back interface + */ +@interface CryptoMIMECallbacks : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (void)onAttachment:(NSString*)headers data:(NSData*)data; +- (void)onBody:(NSString*)body mimetype:(NSString*)mimetype; +/** + * Encrypted headers can be an attachment and thus be placed at the end of the mime structure + */ +- (void)onEncryptedHeaders:(NSString*)headers; +- (void)onError:(NSError*)err; +- (void)onVerified:(long)verified; +@end + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/Key.objc.h b/dist/iOS/Crypto.framework/Versions/A/Headers/Key.objc.h new file mode 100644 index 0000000..0556c1e --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/Key.objc.h @@ -0,0 +1,39 @@ +// Objective-C API for talking to gitlab.com/ProtonMail/go-pm-crypto/key Go package. +// gobind -lang=objc gitlab.com/ProtonMail/go-pm-crypto/key +// +// File is generated by gobind. Do not edit. + +#ifndef __Key_H__ +#define __Key_H__ + +@import Foundation; +#include "Universe.objc.h" + +#include "Armor.objc.h" + +/** + * CheckPassphrase check is private key passphrase ok + */ +FOUNDATION_EXPORT BOOL KeyCheckPassphrase(NSString* privateKey, NSString* passphrase); + +/** + * GetFingerprint get a armored public key fingerprint + */ +FOUNDATION_EXPORT NSString* KeyGetFingerprint(NSString* publicKey, NSError** error); + +/** + * GetFingerprintBinKey get a unarmored public key fingerprint + */ +FOUNDATION_EXPORT NSString* KeyGetFingerprintBinKey(NSData* publicKey, NSError** error); + +/** + * PublicKey get a public key from a private key + */ +FOUNDATION_EXPORT NSString* KeyPublicKey(NSString* privateKey, NSError** error); + +/** + * PublicKeyBinOut get a public key from a private key + */ +FOUNDATION_EXPORT NSData* KeyPublicKeyBinOut(NSString* privateKey, NSError** error); + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/Models.objc.h b/dist/iOS/Crypto.framework/Versions/A/Headers/Models.objc.h new file mode 100644 index 0000000..74fd077 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/Models.objc.h @@ -0,0 +1,91 @@ +// Objective-C API for talking to gitlab.com/ProtonMail/go-pm-crypto/models Go package. +// gobind -lang=objc gitlab.com/ProtonMail/go-pm-crypto/models +// +// File is generated by gobind. Do not edit. + +#ifndef __Models_H__ +#define __Models_H__ + +@import Foundation; +#include "Universe.objc.h" + + +@class ModelsDecryptSignedVerify; +@class ModelsEncryptedSigned; +@class ModelsEncryptedSplit; +@class ModelsSessionSplit; + +/** + * DecryptSignedVerify decrypt_sign_verify + */ +@interface ModelsDecryptSignedVerify : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +/** + * clear text + */ +- (NSString*)plaintext; +- (void)setPlaintext:(NSString*)v; +/** + * bitmask verify status : 0 + */ +- (long)verify; +- (void)setVerify:(long)v; +/** + * error message if verify failed + */ +- (NSString*)message; +- (void)setMessage:(NSString*)v; +@end + +/** + * EncryptedSigned encrypt_sign_package + */ +@interface ModelsEncryptedSigned : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +- (NSString*)encrypted; +- (void)setEncrypted:(NSString*)v; +- (NSString*)signature; +- (void)setSignature:(NSString*)v; +@end + +/** + * EncryptedSplit when encrypt attachemt + */ +@interface ModelsEncryptedSplit : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +- (NSData*)dataPacket; +- (void)setDataPacket:(NSData*)v; +- (NSData*)keyPacket; +- (void)setKeyPacket:(NSData*)v; +- (NSString*)algo; +- (void)setAlgo:(NSString*)v; +@end + +/** + * SessionSplit split session + */ +@interface ModelsSessionSplit : NSObject { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (instancetype)init; +- (NSData*)session; +- (void)setSession:(NSData*)v; +- (NSString*)algo; +- (void)setAlgo:(NSString*)v; +@end + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/ref.h b/dist/iOS/Crypto.framework/Versions/A/Headers/ref.h new file mode 100644 index 0000000..b8036a4 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/ref.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef __GO_REF_HDR__ +#define __GO_REF_HDR__ + +#include + +// GoSeqRef is an object tagged with an integer for passing back and +// forth across the language boundary. A GoSeqRef may represent either +// an instance of a Go object, or an Objective-C object passed to Go. +// The explicit allocation of a GoSeqRef is used to pin a Go object +// when it is passed to Objective-C. The Go seq package maintains a +// reference to the Go object in a map keyed by the refnum along with +// a reference count. When the reference count reaches zero, the Go +// seq package will clear the corresponding entry in the map. +@interface GoSeqRef : NSObject { +} +@property(readonly) int32_t refnum; +@property(strong) id obj; // NULL when representing a Go object. + +// new GoSeqRef object to proxy a Go object. The refnum must be +// provided from Go side. +- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj; + +- (int32_t)incNum; + +@end + +@protocol goSeqRefInterface +-(GoSeqRef*) _ref; +@end + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Headers/universe.objc.h b/dist/iOS/Crypto.framework/Versions/A/Headers/universe.objc.h new file mode 100644 index 0000000..e47f716 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Headers/universe.objc.h @@ -0,0 +1,28 @@ +// Objective-C API for talking to Go package. +// gobind -lang=objc +// +// File is generated by gobind. Do not edit. + +#ifndef __Universe_H__ +#define __Universe_H__ + +@import Foundation; + +@protocol Universeerror; +@class Universeerror; + +@protocol Universeerror +- (NSString*)error; +@end + +@class Universeerror; + +@interface Universeerror : NSError { +} +@property(strong, readonly) id _ref; + +- (instancetype)initWithRef:(id)ref; +- (NSString*)error; +@end + +#endif diff --git a/dist/iOS/Crypto.framework/Versions/A/Modules/module.modulemap b/dist/iOS/Crypto.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..097b6c4 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,12 @@ +framework module "Crypto" { + header "ref.h" + header "Crypto.objc.h" + header "Armor.objc.h" + header "Constants.objc.h" + header "Key.objc.h" + header "Models.objc.h" + header "universe.objc.h" + header "Crypto.h" + + export * +} \ No newline at end of file diff --git a/dist/iOS/Crypto.framework/Versions/A/Resources/Info.plist b/dist/iOS/Crypto.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..0d1a4b8 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/dist/iOS/Crypto.framework/Versions/Current b/dist/iOS/Crypto.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/dist/iOS/Crypto.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/glide.lock b/glide.lock index 428a4b2..6f81f53 100644 --- a/glide.lock +++ b/glide.lock @@ -1,8 +1,10 @@ -hash: 0e0069ce69a4e3bde6233726f21a880347400808a97c2e6f7a173e4d7daea51c -updated: 2018-09-07T10:20:50.211694+02:00 +hash: 7497775ba9a895661860516e3bbf9f367dc7102b014b84d7af225035c0cbfc02 +updated: 2018-10-29T15:51:04.090506+01:00 imports: +- name: github.com/konsorten/go-windows-terminal-sequences + version: 5c8c8bd35d3832f5d134ae1e1e375b69a4d25242 - name: github.com/Sirupsen/logrus - version: 3791101e143bf0f32515ac23e831475684f61229 + version: 566a5f690849162ff53cf98f3c42135389d63f95 - name: golang.org/x/crypto version: 9e4251120d8c43f10024d798bc6dde21d40704a0 repo: https://github.com/ProtonMail/crypto.git @@ -31,12 +33,12 @@ imports: - rsa - ssh/terminal - name: golang.org/x/sys - version: 8cf3aee429924738c56c34bb819c4ea8273fc434 + version: 95b1ffbd15a57cc5abb3f04402b9e8ec0016a52c subpackages: - unix - windows - name: golang.org/x/text - version: 4ae1256249243a4eb350a9a372e126557f2aa346 + version: 6f8607282f41687a5ce9b5a0378084237f2f7576 subpackages: - encoding - encoding/charmap @@ -44,6 +46,6 @@ imports: - encoding/internal/identifier - transform - name: proton/pmmime - version: 347d69204aa62d6958bcb3b9bbacccb24a36372b + version: 72b7b1bf2d1b491e1d003632a0fda41410b0bb59 repo: git@gitlab.protontech.ch:ProtonMail/go-pm-mime.git testImports: [] diff --git a/glide.yaml b/glide.yaml index d62c93c..641b187 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,7 +1,9 @@ -package: proton/pmcrypto +package: gitlab.com/ProtonMail/go-pm-crypto import: - package: golang.org/x/crypto version: v1.0.0 repo: https://github.com/ProtonMail/crypto.git - package: proton/pmmime repo: git@gitlab.protontech.ch:ProtonMail/go-pm-mime.git + version: feat/mimevisitor + diff --git a/init.sh b/init.sh new file mode 100755 index 0000000..643b0ba --- /dev/null +++ b/init.sh @@ -0,0 +1,3 @@ +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +GOPATH="$DIR" glide up +GOPATH="$DIR:$DIR/vendor:$GOPATH" gomobile init -ndk $ANDROID_NDK diff --git a/src/gitlab.com/ProtonMail/go-pm-crypto/armor/armor.go b/src/gitlab.com/ProtonMail/go-pm-crypto/armor/armor.go new file mode 100644 index 0000000..87fc3c9 --- /dev/null +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/armor/armor.go @@ -0,0 +1,62 @@ +package armor + +import ( + "bytes" + "errors" + "gitlab.com/ProtonMail/go-pm-crypto/internal" + "golang.org/x/crypto/openpgp/armor" + "golang.org/x/crypto/openpgp/clearsign" + "io/ioutil" + "gitlab.com/ProtonMail/go-pm-crypto/models" + ) + +// ArmorKey make bytes input key to armor format +func ArmorKey(input []byte) (string, error) { + return ArmorWithType(input, PUBLIC_KEY_HEADER) +} + +// 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, internal.ArmorHeaders) + 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 := internal.Unarmor(input) + if err != nil { + return nil, err + } + return ioutil.ReadAll(b.Body) +} + +//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 +} + +func SplitArmor(encrypted string) (*models.EncryptedSplit, error) { + var err error + b, err := internal.Unarmor(encrypted) + if err != nil { + return nil, err + } + split, err := internal.SplitPackets(b.Body, len(encrypted), -1) + if err != nil { + return nil, err + } + return split, nil +} \ No newline at end of file diff --git a/armor/constants.go b/src/gitlab.com/ProtonMail/go-pm-crypto/armor/constants.go similarity index 100% rename from armor/constants.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/armor/constants.go diff --git a/constants/version.go b/src/gitlab.com/ProtonMail/go-pm-crypto/constants/version.go similarity index 100% rename from constants/version.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/constants/version.go diff --git a/crypto/attachment.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/attachment.go similarity index 63% rename from crypto/attachment.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/attachment.go index f5c8019..5e498b6 100644 --- a/crypto/attachment.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/attachment.go @@ -4,24 +4,50 @@ import ( "bytes" "io" "io/ioutil" - "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/armor" "golang.org/x/crypto/openpgp/packet" - armorUtils "proton/pmcrypto/armor" - "proton/pmcrypto/internal" - "proton/pmcrypto/models" -) + armorUtils "gitlab.com/ProtonMail/go-pm-crypto/armor" + "gitlab.com/ProtonMail/go-pm-crypto/internal" + "gitlab.com/ProtonMail/go-pm-crypto/models" + "sync" + "runtime" + ) + +//EncryptedSplit when encrypt attachment +type AttachmentProcessor struct { + w *io.WriteCloser + pipe *io.PipeWriter + done sync.WaitGroup + split *models.EncryptedSplit + garbageCollector int + err error +} + +func (ap *AttachmentProcessor) Process(plainData []byte) { + (*ap.w).Write(plainData) +} + +func (ap *AttachmentProcessor) Finish() (*models.EncryptedSplit, error) { + if ap.err != nil { + return nil, ap.err + } + (*ap.w).Close() + (*ap.pipe).Close() + ap.done.Wait() + if ap.garbageCollector > 0 { + runtime.GC() + } + return ap.split, nil +} //EncryptAttachmentBinKey ... -func (pm *PmCrypto) EncryptAttachmentBinKey(plainData []byte, fileName string, publicKey []byte) (*models.EncryptedSplit, error) { - - var outBuf bytes.Buffer - w, err := armor.Encode(&outBuf, armorUtils.MESSAGE_HEADER, internal.ArmorHeaders) - if err != nil { - return nil, err - } - +func (pm *PmCrypto) encryptAttachment(estimatedSize int, fileName string, publicKey []byte, garbageCollector int) (*AttachmentProcessor, error) { + attachmentProc := &AttachmentProcessor{} + // you can also add these one at + // a time if you need to + attachmentProc.done.Add(1) + attachmentProc.garbageCollector = garbageCollector pubKeyReader := bytes.NewReader(publicKey) pubKeyEntries, err := openpgp.ReadKeyRing(pubKeyReader) if err != nil { @@ -36,18 +62,28 @@ func (pm *PmCrypto) EncryptAttachmentBinKey(plainData []byte, fileName string, p Time: pm.getTimeGenerator(), } - ew, err := openpgp.Encrypt(w, pubKeyEntries, nil, hints, config) + reader, writer := io.Pipe() - _, _ = ew.Write(plainData) - ew.Close() - w.Close() + go func () { + defer attachmentProc.done.Done() + split, splitError := internal.SplitPackets(reader, estimatedSize, garbageCollector) + if attachmentProc.err != nil { + attachmentProc.err = splitError + } + split.Algo = "aes256" + attachmentProc.split = split + }() - split, err := armorUtils.SplitArmor(outBuf.String()) - if err != nil { - return nil, err + var ew io.WriteCloser + var encryptErr error + ew, encryptErr = openpgp.Encrypt(writer, pubKeyEntries, nil, hints, config) + attachmentProc.w = &ew + attachmentProc.pipe = writer + if attachmentProc.err != nil { + attachmentProc.err = encryptErr } - split.Algo = "aes256" - return split, nil + + return attachmentProc, nil } //EncryptAttachment ... @@ -56,7 +92,26 @@ func (pm *PmCrypto) EncryptAttachment(plainData []byte, fileName string, publicK if err != nil { return nil, err } - return pm.EncryptAttachmentBinKey(plainData, fileName, rawPubKey) + ap, err := pm.encryptAttachment(len(plainData), fileName, rawPubKey, -1) + if err != nil { + return nil, err + } + ap.Process(plainData) + split, err := ap.Finish() + if err != nil { + return nil, err + } + return split, nil +} + +//EncryptAttachment ... +func (pm *PmCrypto) EncryptAttachmentLowMemory(estimatedSize int, fileName string, publicKey string) (*AttachmentProcessor, error) { + rawPubKey, err := armorUtils.Unarmor(publicKey) + if err != nil { + return nil, err + } + // Garbage collect every megabyte + return pm.encryptAttachment(estimatedSize, fileName, rawPubKey, 1 << 20) } //DecryptAttachmentBinKey ... diff --git a/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/attachment_test.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/attachment_test.go new file mode 100644 index 0000000..106095f --- /dev/null +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/attachment_test.go @@ -0,0 +1,67 @@ +package crypto + +import ( + "testing" +) + +const publicKeya = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +OQTmvM6R +=DvFv +-----END PGP PUBLIC KEY BLOCK-----` + + +func TestEncrypt(t *testing.T) { + o := PmCrypto{} + split, err := o.EncryptAttachment([]byte("Hello World!"), "File name", publicKeya) + if err != nil || split == nil { + panic("Encryption failed") + } +} \ No newline at end of file diff --git a/crypto/key.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/key.go similarity index 99% rename from crypto/key.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/key.go index a418ec2..6ab6ce6 100644 --- a/crypto/key.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/key.go @@ -11,7 +11,7 @@ import ( "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" "math/big" - "proton/pmcrypto/armor" + "gitlab.com/ProtonMail/go-pm-crypto/armor" ) const ( diff --git a/crypto/message.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/message.go similarity index 98% rename from crypto/message.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/message.go index e2bd6fb..9a2a696 100644 --- a/crypto/message.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/message.go @@ -13,9 +13,9 @@ import ( errors2 "golang.org/x/crypto/openpgp/errors" "golang.org/x/crypto/openpgp/packet" "math" - armorUtils "proton/pmcrypto/armor" - "proton/pmcrypto/internal" - "proton/pmcrypto/models" + armorUtils "gitlab.com/ProtonMail/go-pm-crypto/armor" + "gitlab.com/ProtonMail/go-pm-crypto/internal" + "gitlab.com/ProtonMail/go-pm-crypto/models" ) // DecryptMessage decrypt encrypted message use private key (string ) diff --git a/crypto/mime.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/mime.go similarity index 97% rename from crypto/mime.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/mime.go index 3ad5ec7..f1dfc4f 100644 --- a/crypto/mime.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/mime.go @@ -9,8 +9,7 @@ import ( "io/ioutil" "bytes" "golang.org/x/crypto/openpgp" - "proton/pmcrypto/armor" -) + ) // ======================== Attachments Collector ============== // Collect contents of all attachment parts and return @@ -34,7 +33,6 @@ func (pm PmCrypto) parseMIME(mimeBody string, verifierKey []byte) (*pmmime.BodyC bodyCollector := pmmime.NewBodyCollector(printAccepter) attachmentsCollector := pmmime.NewAttachmentsCollector(bodyCollector) mimeVisitor := pmmime.NewMimeVisitor(attachmentsCollector) - str, err := armor.ArmorKey(verifierKey) signatureCollector := newSignatureCollector(mimeVisitor, pubKeyEntries, config) err = pmmime.VisitAll(bytes.NewReader(mmBodyData), h, signatureCollector) diff --git a/crypto/mime_test.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/mime_test.go similarity index 99% rename from crypto/mime_test.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/mime_test.go index d2718ae..21156b7 100644 --- a/crypto/mime_test.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/mime_test.go @@ -3,7 +3,7 @@ package crypto import ( "fmt" "io/ioutil" - "proton/pmcrypto/internal" + "gitlab.com/ProtonMail/go-pm-crypto/internal" "testing" ) diff --git a/crypto/pmcrypto.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/pmcrypto.go similarity index 100% rename from crypto/pmcrypto.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/pmcrypto.go diff --git a/crypto/session.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/session.go similarity index 98% rename from crypto/session.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/session.go index f1188b5..10bbd0f 100644 --- a/crypto/session.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/session.go @@ -9,8 +9,8 @@ import ( "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" - "proton/pmcrypto/armor" - "proton/pmcrypto/models" + "gitlab.com/ProtonMail/go-pm-crypto/armor" + "gitlab.com/ProtonMail/go-pm-crypto/models" ) //RandomToken ... diff --git a/crypto/sign_detached.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/sign_detached.go similarity index 99% rename from crypto/sign_detached.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/sign_detached.go index 14772d6..8503b40 100644 --- a/crypto/sign_detached.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/sign_detached.go @@ -10,7 +10,7 @@ import ( "golang.org/x/crypto/openpgp/packet" errors2 "golang.org/x/crypto/openpgp/errors" "io" - "proton/pmcrypto/internal" + "gitlab.com/ProtonMail/go-pm-crypto/internal" ) // SignTextDetached sign detached text type diff --git a/crypto/signature_collector.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/signature_collector.go similarity index 99% rename from crypto/signature_collector.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/signature_collector.go index bd1d544..4cd862c 100644 --- a/crypto/signature_collector.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/signature_collector.go @@ -1,14 +1,12 @@ package crypto import ( - "bufio" "bytes" "golang.org/x/crypto/openpgp" "golang.org/x/crypto/openpgp/packet" "io" "io/ioutil" "mime" - "mime/multipart" "net/textproto" "proton/pmmime" ) diff --git a/crypto/time.go b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/time.go similarity index 57% rename from crypto/time.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/crypto/time.go index a2e980d..06ab0a4 100644 --- a/crypto/time.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/crypto/time.go @@ -7,7 +7,6 @@ import ( // UpdateTime update cached time func (pm *PmCrypto) UpdateTime(newTime int64) { pm.latestServerTime = newTime - pm.latestClientTime = time.Now() } //GetTime get latest cached time @@ -16,10 +15,8 @@ func (pm *PmCrypto) GetTime() int64 { } func (pm *PmCrypto) getNow() time.Time { - if pm.latestServerTime > 0 && !pm.latestClientTime.IsZero() { - // Sub is monotome, it uses a monotime time clock in this case instead of the wall clock - extrapolate := int64(pm.latestClientTime.Sub(time.Now()).Seconds()) - return time.Unix(pm.latestServerTime + extrapolate, 0) + if pm.latestServerTime > 0 { + return time.Unix(pm.latestServerTime, 0) } return time.Now() diff --git a/internal/armor.go b/src/gitlab.com/ProtonMail/go-pm-crypto/internal/armor.go similarity index 100% rename from internal/armor.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/internal/armor.go diff --git a/internal/common.go b/src/gitlab.com/ProtonMail/go-pm-crypto/internal/common.go similarity index 100% rename from internal/common.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/internal/common.go diff --git a/src/gitlab.com/ProtonMail/go-pm-crypto/internal/packets.go b/src/gitlab.com/ProtonMail/go-pm-crypto/internal/packets.go new file mode 100644 index 0000000..1327b01 --- /dev/null +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/internal/packets.go @@ -0,0 +1,115 @@ +package internal + +import ( + "bytes" + "golang.org/x/crypto/openpgp/packet" + "gitlab.com/ProtonMail/go-pm-crypto/models" + "io" + "runtime" + ) + +func SplitPackets(encryptedReader io.Reader, estimatedLength int, garbageCollector int) (*models.EncryptedSplit, error){ + var err error + + // For info on each, see: https://golang.org/pkg/runtime/#MemStats + //kr *KeyRing, r io.Reader) (key *SymmetricKey, symEncryptedData []byte, + packets := packet.NewReader(encryptedReader) + + outSplit := &models.EncryptedSplit{} + gcCounter := 0 + + // 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: + // The code below is optimized to not + var b bytes.Buffer + // 2^16 is an estimation of the size difference between input and output, the size difference is most probably + // 16 bytes at a maximum though. + // We need to avoid triggering a grow from the system as this will allocate too much memory causing problems + // in low-memory environments + b.Grow(1 << 16 + estimatedLength) + // empty encoded length + start byte + b.Write(make([]byte, 6)) + b.WriteByte(byte(1)) + actualLength := 1 + block := make([]byte, 128) + for { + n, err := p.Contents.Read(block) + if err == io.EOF { + break + } + b.Write(block[:n]) + actualLength += n + gcCounter += n + if gcCounter > garbageCollector && garbageCollector > 0 { + runtime.GC() + gcCounter = 0 + } + } + + // quick encoding + symEncryptedData := b.Bytes() + if actualLength < 192 { + symEncryptedData[4] = byte(210) + symEncryptedData[5] = byte(actualLength) + symEncryptedData = symEncryptedData[4:] + } else if actualLength < 8384 { + actualLength = actualLength - 192 + symEncryptedData[3] = byte(210) + symEncryptedData[4] = 192+byte(actualLength>>8) + symEncryptedData[5] = byte(actualLength) + symEncryptedData = symEncryptedData[3:] + } else { + symEncryptedData[0] = byte(210) + symEncryptedData[1] = byte(255) + symEncryptedData[2] = byte(actualLength>>24) + symEncryptedData[3] = byte(actualLength>>16) + symEncryptedData[4] = byte(actualLength>>8) + symEncryptedData[5] = byte(actualLength) + } + + outSplit.DataPacket = symEncryptedData + break + + } + } + + var buf bytes.Buffer + ek.Serialize(&buf) + outSplit.KeyPacket = buf.Bytes() + + return outSplit, err +} + +//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 +} diff --git a/key/fingerprint.go b/src/gitlab.com/ProtonMail/go-pm-crypto/key/fingerprint.go similarity index 94% rename from key/fingerprint.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/key/fingerprint.go index 08394c3..9632cb2 100644 --- a/key/fingerprint.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/key/fingerprint.go @@ -6,7 +6,7 @@ import ( "errors" "golang.org/x/crypto/openpgp" - "proton/pmcrypto/armor" + "gitlab.com/ProtonMail/go-pm-crypto/armor" ) // GetFingerprint get a armored public key fingerprint diff --git a/key/key.go b/src/gitlab.com/ProtonMail/go-pm-crypto/key/key.go similarity index 97% rename from key/key.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/key/key.go index b54f83e..bf3cde0 100644 --- a/key/key.go +++ b/src/gitlab.com/ProtonMail/go-pm-crypto/key/key.go @@ -6,7 +6,7 @@ import ( "fmt" "golang.org/x/crypto/openpgp/packet" "bytes" - "proton/pmcrypto/armor" + "gitlab.com/ProtonMail/go-pm-crypto/armor" ) //CheckPassphrase check is private key passphrase ok diff --git a/models/models.go b/src/gitlab.com/ProtonMail/go-pm-crypto/models/models.go similarity index 100% rename from models/models.go rename to src/gitlab.com/ProtonMail/go-pm-crypto/models/models.go