From 9f130a80b7767c84e6bef0e0e9e73e08bbc9d82a Mon Sep 17 00:00:00 2001 From: ycc Date: Tue, 31 Mar 2026 21:32:46 +0200 Subject: [PATCH] sequences update and async crypto keys optimization --- asymcrypt.go | 74 ++++++++++++++---------- doc/invitation/sq_invitation.puml | 11 ++-- doc/invitation/sq_invitation_calls.puml | 9 +++ doc/invitation/sq_server_invitation.puml | 14 +++++ doc/invitation/sq_srvinv00.puml | 15 +++++ doc/invitation/sq_srvinv01.puml | 15 +++-- pb/messages.proto | 18 +++--- 7 files changed, 102 insertions(+), 54 deletions(-) create mode 100644 doc/invitation/sq_invitation_calls.puml create mode 100644 doc/invitation/sq_server_invitation.puml create mode 100644 doc/invitation/sq_srvinv00.puml diff --git a/asymcrypt.go b/asymcrypt.go index 03da23d..bf47306 100644 --- a/asymcrypt.go +++ b/asymcrypt.go @@ -23,16 +23,20 @@ func NewKeyPair() (*KeyPair, error) { // Return error! if err != nil { return nil, fmt.Errorf("key generation failed: %w", err) } - pub, err := keys.GetArmoredPublicKey() + pubKey, err := keys.ToPublic() if err != nil { - return nil, fmt.Errorf("gopenpgp: unable to get public key: %w", err) + return nil, fmt.Errorf("gopenpgp: unable to extract public key: %w", err) } - priv, err := keys.Armor() + pubBytes, err := pubKey.Serialize() if err != nil { - return nil, fmt.Errorf("failed to armor private key: %w", err) + return nil, fmt.Errorf("gopenpgp: unable to serialize public key: %w", err) } - kp.Public = base64.StdEncoding.EncodeToString([]byte(pub)) - kp.Private = base64.StdEncoding.EncodeToString([]byte(priv)) + privBytes, err := keys.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to serialize private key: %w", err) + } + kp.Public = base64.StdEncoding.EncodeToString(pubBytes) + kp.Private = base64.StdEncoding.EncodeToString(privBytes) kp.Generated = time.Now() return &kp, nil } @@ -42,9 +46,9 @@ func (Kp *KeyPair) GetCryptoKeyObject() (*crypto.Key, error) { if err != nil { return nil, fmt.Errorf("failed to decode private key: %w", err) } - key, err := crypto.NewKeyFromArmored(string(priv)) + key, err := crypto.NewKey(priv) if err != nil { - return nil, fmt.Errorf("Ccreate key from armoured failed: %w", err) + return nil, fmt.Errorf("create key from binary failed: %w", err) } return key, nil } @@ -54,7 +58,7 @@ func AsymEncrypt(publicKey string, data []byte) ([]byte, error) { if err != nil { return nil, fmt.Errorf("Message encryption b64 failed: %w", err) } - ciphertext, err := encryptMessage(string(pub), crypto.NewPlainMessage(data)) + ciphertext, err := encryptMessage(pub, crypto.NewPlainMessage(data)) if err != nil { return nil, fmt.Errorf("Message encryption failed: %w", err) } @@ -67,7 +71,7 @@ func AsymDecrypt(PrivateKey string, data []byte) ([]byte, error) { if err != nil { return nil, fmt.Errorf("Message decryption b64 failed: %w", err) } - decrypted, err := decryptMessage(string(priv), nil, crypto.NewPGPMessage(data)) + decrypted, err := decryptMessage(priv, nil, crypto.NewPGPMessage(data)) if err != nil { return nil, fmt.Errorf("Message decryption failed: %w", err) } @@ -79,7 +83,15 @@ func AsymEncryptArmored(PublicKey string, data []byte) ([]byte, error) { if err != nil { return nil, fmt.Errorf("Message encryption b64 failed: %w", err) } - armor, err := helper.EncryptBinaryMessageArmored(string(pub), data) + pubKey, err := crypto.NewKey(pub) + if err != nil { + return nil, fmt.Errorf("Message encryption key parse failed: %w", err) + } + armoredPub, err := pubKey.GetArmoredPublicKey() + if err != nil { + return nil, fmt.Errorf("Message encryption key armor failed: %w", err) + } + armor, err := helper.EncryptBinaryMessageArmored(armoredPub, data) if err != nil { return nil, fmt.Errorf("Message encryption failed: %w", err) } @@ -91,7 +103,15 @@ func AsymDecryptArmored(PrivateKey string, data []byte) ([]byte, error) { if err != nil { return nil, fmt.Errorf("Message decryption b64 failed: %w", err) } - decrypted, err := helper.DecryptBinaryMessageArmored(string(priv), nil, string(data)) + privKey, err := crypto.NewKey(priv) + if err != nil { + return nil, fmt.Errorf("Message decryption key parse failed: %w", err) + } + armoredPriv, err := privKey.Armor() + if err != nil { + return nil, fmt.Errorf("Message decryption key armor failed: %w", err) + } + decrypted, err := helper.DecryptBinaryMessageArmored(armoredPriv, nil, string(data)) if err != nil { return nil, fmt.Errorf("Message decryption failed: %w", err) } @@ -134,7 +154,7 @@ func AsymDecryptArmored(PrivateKey string, data []byte) ([]byte, error) { return DecryptedMessage, err } */ -func encryptMessage(key string, message *crypto.PlainMessage) (*crypto.PGPMessage, error) { +func encryptMessage(key []byte, message *crypto.PlainMessage) (*crypto.PGPMessage, error) { publicKeyRing, err := createPublicKeyRing(key) if err != nil { return nil, err @@ -148,8 +168,8 @@ func encryptMessage(key string, message *crypto.PlainMessage) (*crypto.PGPMessag return ciphertext, nil } -func decryptMessage(privateKey string, passphrase []byte, ciphertext *crypto.PGPMessage) (*crypto.PlainMessage, error) { - privateKeyObj, err := crypto.NewKeyFromArmored(privateKey) +func decryptMessage(privateKey []byte, passphrase []byte, ciphertext *crypto.PGPMessage) (*crypto.PlainMessage, error) { + privateKeyObj, err := crypto.NewKey(privateKey) if err != nil { return nil, fmt.Errorf("gopenpgp: unable to parse the private key: %w", err) } @@ -174,8 +194,8 @@ func decryptMessage(privateKey string, passphrase []byte, ciphertext *crypto.PGP return message, nil } -func createPublicKeyRing(publicKey string) (*crypto.KeyRing, error) { - publicKeyObj, err := crypto.NewKeyFromArmored(publicKey) +func createPublicKeyRing(publicKey []byte) (*crypto.KeyRing, error) { + publicKeyObj, err := crypto.NewKey(publicKey) if err != nil { return nil, fmt.Errorf("gopenpgp: unable to parse public key: %w", err) } @@ -205,7 +225,7 @@ func AsymEncryptAndSign(PublicEncryptionKey string, PrivateSignatureKey string, if err != nil { return nil, fmt.Errorf("Message encryption and sign b64 failed: %w", err) } - ciphertext, signature, err := encryptAndSignMessage(string(pub), string(priv), crypto.NewPlainMessage(data)) + ciphertext, signature, err := encryptAndSignMessage(pub, priv, crypto.NewPlainMessage(data)) if err != nil { return nil, fmt.Errorf("Message encryption failed: %w", err) } @@ -223,14 +243,14 @@ func AsymDecryptAndCheck(MyPrivateEncryptionKey string, MyContactPublicKey strin if err != nil { return nil, fmt.Errorf("Message decryption and sign b64 failed: %w", err) } - DecryptedMessage, err = decryptAndCheckMessage(string(pub), string(priv), crypto.NewPGPMessage(data), crypto.NewPGPSignature(Signature)) + DecryptedMessage, err = decryptAndCheckMessage(pub, priv, crypto.NewPGPMessage(data), crypto.NewPGPSignature(Signature)) if err != nil { return nil, fmt.Errorf("Message decryption and sign failed: %w", err) } return DecryptedMessage, err } -func encryptAndSignMessage(pub string, priv string, message *crypto.PlainMessage) (*crypto.PGPMessage, []byte, error) { +func encryptAndSignMessage(pub []byte, priv []byte, message *crypto.PlainMessage) (*crypto.PGPMessage, []byte, error) { var privateKeyObj, unlockedKeyObj *crypto.Key var privateKeyRing *crypto.KeyRing publicKeyRing, err := createPublicKeyRing(pub) @@ -238,11 +258,7 @@ func encryptAndSignMessage(pub string, priv string, message *crypto.PlainMessage return nil, nil, err } - if err != nil { - return nil, nil, fmt.Errorf("gopenpgp: unable to encrypt message") - } - - if privateKeyObj, err = crypto.NewKeyFromArmored(priv); err != nil { + if privateKeyObj, err = crypto.NewKey(priv); err != nil { return nil, nil, fmt.Errorf("gopenpgp: unable to parse private key") } @@ -267,7 +283,7 @@ func encryptAndSignMessage(pub string, priv string, message *crypto.PlainMessage return ciphertext, signature.GetBinary(), nil } -func decryptAndCheckMessage(pub string, priv string, message *crypto.PGPMessage, signature *crypto.PGPSignature) ([]byte, error) { +func decryptAndCheckMessage(pub []byte, priv []byte, message *crypto.PGPMessage, signature *crypto.PGPSignature) ([]byte, error) { var privateKeyObj, unlockedKeyObj *crypto.Key var privateKeyRing *crypto.KeyRing publicKeyRing, err := createPublicKeyRing(pub) @@ -275,11 +291,7 @@ func decryptAndCheckMessage(pub string, priv string, message *crypto.PGPMessage, return nil, err } - if err != nil { - return nil, fmt.Errorf("gopenpgp: unable to encrypt message") - } - - if privateKeyObj, err = crypto.NewKeyFromArmored(priv); err != nil { + if privateKeyObj, err = crypto.NewKey(priv); err != nil { return nil, fmt.Errorf("gopenpgp: unable to parse private key") } diff --git a/doc/invitation/sq_invitation.puml b/doc/invitation/sq_invitation.puml index f2de159..c6ec40f 100644 --- a/doc/invitation/sq_invitation.puml +++ b/doc/invitation/sq_invitation.puml @@ -1,7 +1,6 @@ -@startuml Server Invitation Step 01 -Bob -> MeowBob: Create invitation for alice (Generate Bob ContactCard and create Alice pending contact) -Bob -> Alice: Send invitation (Bob ContactCard) -Alice -> MeowAlice: Accept Invitation and create answer (Generate Alice ContactCard and create finalized Bob contact) -Alice -> Bob: Send answer (Alice ContactCard) -Bob -> MeowBob: Review Answer, invitation finalize (Finalize Alice contact and notify Alice that communication is possible) +@startuml General Invitation Steps +InitiatingUser -> InvitedUser: STEP_1=InitiatingUser_TmpId generate a public key, invitation uid & message for InvitedUser optionnally password protected +InvitedUser -> InitiatingUser: STEP_2=InvitedUser_Id Create invitation for alice (Generate InvitedUser ContactCard and create InitiatingUser pending contact) +InitiatingUser -> InvitedUser: STEP_3=InitiatingUser_Id Accept Invitation and create answer (Generate InitiatingUser ContactCard and create finalized InvitedUser contact) +InvitedUser -> InitiatingUser: STEP_4=InvitedUser_OK Review Answer, invitation finalize (Finalize InitiatingUser contact and notify InitiatingUser that communication is possible) @enduml \ No newline at end of file diff --git a/doc/invitation/sq_invitation_calls.puml b/doc/invitation/sq_invitation_calls.puml new file mode 100644 index 0000000..fcefe5d --- /dev/null +++ b/doc/invitation/sq_invitation_calls.puml @@ -0,0 +1,9 @@ +@startuml Detailled Invitation Steps +InitiatingUser -> MeowInitiatingUser: STEP 1 generate a public key & message for InvitedUser optionnally password protected +InitiatingUser -> InvitedUser: send public key +InvitedUser -> MeowInvitedUser: STEP 2 Create invitation for alice (Generate InvitedUser ContactCard and create InitiatingUser pending contact) +InvitedUser -> InitiatingUser: Send invitation (InvitedUser ContactCard encrypted with InitiatingUser public key) +InitiatingUser -> MeowInitiatingUser: STEP 3 Accept Invitation and create answer (Generate InitiatingUser ContactCard and create finalized InvitedUser contact) +InitiatingUser -> InvitedUser: Send answer (InitiatingUser ContactCard) +InvitedUser -> MeowInvitedUser: STEP 4 Review Answer, invitation finalize (Finalize InitiatingUser contact and notify InitiatingUser that communication is possible) +@enduml \ No newline at end of file diff --git a/doc/invitation/sq_server_invitation.puml b/doc/invitation/sq_server_invitation.puml new file mode 100644 index 0000000..17812d9 --- /dev/null +++ b/doc/invitation/sq_server_invitation.puml @@ -0,0 +1,14 @@ +@startuml General Server Invitation Steps +InitiatingUser -> InitiatingUser: STEP_1.1 Create STEP_1_data=InitiatingUser_TmpId (public key & message for InvitedUser optionnally passwords (url & payload) protected) +InitiatingUser -> Server: STEP_1.2 Send STEP_1_data to server +Server -> InvitedUser: STEP_1.3 Get STEP_1_data from server +InvitedUser -> InvitedUser: STEP_2.1 Create STEP_2_data=InvitedUser_Id for InitiatingUser (Generate InvitedUser ContactCard and create InitiatingUser pending contact) +InvitedUser -> Server: STEP_2.1 Send STEP_2_data to server +Server -> InitiatingUser: STEP_2.3 Get STEP_2_data from server +InitiatingUser -> InitiatingUser: STEP_3 Create STEP_3_data=InitiatingUser_Id (Generate InitiatingUser ContactCard and create finalized InvitedUser contact) +InitiatingUser -> Server: STEP_3.1 Send STEP_3_data to server +Server -> InvitedUser: STEP_3.3 Get STEP_3_data from server +InvitedUser -> InvitedUser: STEP_4 Create STEP_4_data=InvitedUser_OK Review Answer, invitation finalize (Finalize InitiatingUser contact and notify InitiatingUser that communication is possible) +InvitedUser -> Server: STEP_4.1 Send STEP_4_data to server +Server -> InitiatingUser: STEP_4.3 Get STEP_4_data from server +@enduml \ No newline at end of file diff --git a/doc/invitation/sq_srvinv00.puml b/doc/invitation/sq_srvinv00.puml new file mode 100644 index 0000000..6b261e6 --- /dev/null +++ b/doc/invitation/sq_srvinv00.puml @@ -0,0 +1,15 @@ +@startuml Server Invitation Step 00 +InitiatingUser -> Bastet : contact name +InitiatingUser -> Bastet : invitationMessage +InitiatingUser -> Bastet : select invitation server +InitiatingUser -> Bastet : optional password +Bastet -> NativeLib : send invitation +NativeLib -> NativeLib : create contact and invtation KP +NativeLib -> Server : send invitation +Server -> Server : create invtation URL +Server -> Redis : store InitiatingUser pub key and message/pwd +Server -> NativeLib : invitation URL +NativeLib -> Bastet : invitation URL +Bastet -> InitiatingUser : invitation URL +InitiatingUser -> InvitedUser : invitation URL +@enduml \ No newline at end of file diff --git a/doc/invitation/sq_srvinv01.puml b/doc/invitation/sq_srvinv01.puml index 67c2e14..8687742 100644 --- a/doc/invitation/sq_srvinv01.puml +++ b/doc/invitation/sq_srvinv01.puml @@ -1,12 +1,11 @@ @startuml Server Invitation Step 01 -User -> Bastet : fill invitation -User -> Bastet : select servers +InvitedUser -> Bastet : provide invitation URL +Bastet -> NativeLib : GET InitiatingUser pub key and message +InvitedUser -> Bastet : fill invitation +InvitedUser -> Bastet : select servers Bastet -> NativeLib : get server cards for selected uids NativeLib -> Bastet : server cards -Bastet -> NativeLib : invitationCreateMessage -NativeLib -> Bastet : invitationMessage -Bastet -> Server : send invitation -Server -> Redis : Store invitation -Server -> Bastet : invitation URL -Bastet -> User : invitation URL +Bastet -> NativeLib : invitation data & InitiatingUser pub key +NativeLib -> Server : POST encrypted invitation +Server -> Redis : Store invitation data @enduml \ No newline at end of file diff --git a/pb/messages.proto b/pb/messages.proto index d6ed887..84b481c 100644 --- a/pb/messages.proto +++ b/pb/messages.proto @@ -22,15 +22,15 @@ message PackedServerMessage { // structure to hold an invitation through a server message Invitation { - bytes payload = 1; // invitation payload, encrypted after step 2 - int32 timeout = 2; // how long do I want the invitation to remain available on the server - int32 shortcodeLen = 3; // len of the shortcode you wish for short url transmission - string shortcode = 4; // shortcode that the friend shall request to get the invitation - string password = 5; // password to set for accessing invitation (optional) - string uuid = 6; // id that the friend gave you, that you should include to your reply to get recognized - int64 expiry = 7; // the server allowed expiry date, it may be samller than the requested timeout according to server policy - int32 step = 8; // progress in the inviattion process : 1=invite friend, 2=friend requests invitation, 3=friend's answer - string from = 9; // used in step 3 the answer public key to check the signature in user message + bytes payload = 1; // invitation payload, optionaly encrypted with payload password(transmitted OOB) on step 1 + int32 timeout = 2; // how long do I want the invitation to remain available on the server + int32 shortcode_len = 3; // len of the shortcode you wish for short url transmission + string shortcode = 4; // shortcode that the friend shall request to get the invitation + string password = 5; // optional password(transmitted OOB) to set for accessing invitation (server check) + string uuid = 6; // invitation uuid + int64 expiry = 7; // the server allowed expiry date, it may be smaller than the requested timeout according to server policy + int32 step = 8; // progress in the invitation process : 1=initiator pub key, 2=invited data enc with pub key, 3=initator data full encrypted, 4=invited All OK ! + string from = 9; // used in step 1 the public key to encrypt step 2 message } // structure for requesting incoming messages