Skip to content

Commit

Permalink
Release v0.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
champo committed Jan 4, 2021
1 parent 333256b commit dd796f7
Show file tree
Hide file tree
Showing 184 changed files with 69,032 additions and 416 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
libwallet/.gitignore# binary
libwallet
.build

17 changes: 0 additions & 17 deletions .vscode/launch.json

This file was deleted.

5 changes: 0 additions & 5 deletions .vscode/settings.json

This file was deleted.

56 changes: 40 additions & 16 deletions challenge_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ type ChallengePrivateKey struct {
key *btcec.PrivateKey
}

type encryptedPrivateKey struct {
Version uint8
Birthday uint16
EphPublicKey []byte // 33-byte compressed public-key
CipherText []byte // 64-byte encrypted text
Salt []byte // (optional) 8-byte salt
}

type DecryptedPrivateKey struct {
Key *HDPrivateKey
Birthday int
Expand Down Expand Up @@ -53,8 +61,32 @@ func (k *ChallengePrivateKey) PubKey() *ChallengePublicKey {
}

func (k *ChallengePrivateKey) DecryptKey(encryptedKey string, network *Network) (*DecryptedPrivateKey, error) {
decoded, err := decodeEncryptedPrivateKey(encryptedKey)
if err != nil {
return nil, err
}

plaintext, err := decryptWithPrivKey(k.key, decoded.EphPublicKey, decoded.CipherText)
if err != nil {
return nil, err
}

reader := bytes.NewReader(base58.Decode(encryptedKey))
rawPrivKey := plaintext[0:32]
rawChainCode := plaintext[32:]

privKey, err := NewHDPrivateKeyFromBytes(rawPrivKey, rawChainCode, network)
if err != nil {
return nil, errors.Wrapf(err, "decrypting key: failed to parse key")
}

return &DecryptedPrivateKey{
privKey,
int(decoded.Birthday),
}, nil
}

func decodeEncryptedPrivateKey(encodedKey string) (*encryptedPrivateKey, error) {
reader := bytes.NewReader(base58.Decode(encodedKey))
version, err := reader.ReadByte()
if err != nil {
return nil, errors.Wrapf(err, "decrypting key")
Expand Down Expand Up @@ -89,21 +121,13 @@ func (k *ChallengePrivateKey) DecryptKey(encryptedKey string, network *Network)
return nil, errors.Errorf("decrypting key: failed to read recoveryCodeSalt")
}

plaintext, err := decryptWithPrivKey(k.key, rawPubEph, ciphertext)
if err != nil {
return nil, err
result := &encryptedPrivateKey{
Version: version,
Birthday: birthday,
EphPublicKey: rawPubEph,
CipherText: ciphertext,
Salt: recoveryCodeSalt,
}

rawPrivKey := plaintext[0:32]
rawChainCode := plaintext[32:]

privKey, err := NewHDPrivateKeyFromBytes(rawPrivKey, rawChainCode, network)
if err != nil {
return nil, errors.Wrapf(err, "decrypting key: failed to parse key")
}

return &DecryptedPrivateKey{
privKey,
int(birthday),
}, nil
return result, nil
}
121 changes: 113 additions & 8 deletions emergency_kit.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,137 @@
package libwallet

import (
"encoding/hex"
"encoding/json"
"fmt"

"github.com/muun/libwallet/emergencykit"
)

// EKInput input struct to fill the PDF
type EKInput struct {
FirstEncryptedKey string
FirstFingerprint string
SecondEncryptedKey string
SecondFingerprint string
}

// EKOutput with the html as string and the verification code
type EKOutput struct {
HTML string
VerificationCode string
Metadata string
}

// GenerateEmergencyKitHTML returns the translated html as a string along with the verification code
// GenerateEmergencyKitHTML returns the translated html as a string along with the verification
// code and the kit metadata, represented in an opaque string.
// After calling this method, clients should use their Chromium/WebKit implementations to render
// the HTML into a PDF (better done there), and then come back to call `AddEmergencyKitMetadata`
// and produce the final PDF (better done here).
func GenerateEmergencyKitHTML(ekParams *EKInput, language string) (*EKOutput, error) {
out, err := emergencykit.GenerateHTML(&emergencykit.Input{
moduleInput := &emergencykit.Input{
FirstEncryptedKey: ekParams.FirstEncryptedKey,
FirstFingerprint: ekParams.FirstFingerprint,
SecondEncryptedKey: ekParams.SecondEncryptedKey,
}, language)
SecondFingerprint: ekParams.SecondFingerprint,
}

// Create the HTML and the verification code:
htmlWithCode, err := emergencykit.GenerateHTML(moduleInput, language)
if err != nil {
return nil, fmt.Errorf("GenerateEkHtml failed to render: %w", err)
}

// Create and serialize the metadata:
metadata, err := createEmergencyKitMetadata(ekParams)
if err != nil {
return nil, fmt.Errorf("GenerateEkHtml failed to create metadata: %w", err)
}

metadataBytes, err := json.Marshal(&metadata)
if err != nil {
return nil, fmt.Errorf("GenerateEkHtml failed to marshal %s: %w", string(metadataBytes), err)
}

output := &EKOutput{
HTML: htmlWithCode.HTML,
VerificationCode: htmlWithCode.VerificationCode,
Metadata: string(metadataBytes),
}

return output, nil
}

// AddEmergencyKitMetadata produces a copy of the PDF file at `srcFile` with embedded metadata,
// writing it into `dstFile`. The provided metadata must be the same opaque string produced by
// `GenerateEmergencyKitHTML`.
func AddEmergencyKitMetadata(metadataText string, srcFile string, dstFile string) error {
// Initialize the MetadataWriter:
metadataWriter := &emergencykit.MetadataWriter{
SrcFile: srcFile,
DstFile: dstFile,
}

// Deserialize the metadata:
var metadata emergencykit.Metadata

err := json.Unmarshal([]byte(metadataText), &metadata)
if err != nil {
return fmt.Errorf("AddEkMetadata failed to unmarshal: %w", err)
}

err = metadataWriter.WriteMetadata(&metadata)
if err != nil {
return fmt.Errorf("AddEkMetadata failed to write metadata: %w", err)
}

return nil
}

func createEmergencyKitMetadata(ekParams *EKInput) (*emergencykit.Metadata, error) {
// NOTE:
// This method would be more naturally placed in the `emergencykit` module, but given the current
// project structure (heavily determined by `gomobile` and the need for top-level bindings) and
// the use of `decodeEncryptedPrivateKey` this isn't possible. Instead, we peek through the layer
// boundary to craft the object here.

// Decode both keys, to extract their inner properties:
firstKey, err := decodeEncryptedPrivateKey(ekParams.FirstEncryptedKey)
if err != nil {
return nil, fmt.Errorf("createEkMetadata failed to decode first key: %w", err)
}

secondKey, err := decodeEncryptedPrivateKey(ekParams.SecondEncryptedKey)
if err != nil {
return nil, err
return nil, fmt.Errorf("createEkMetadata failed to decode second key: %w", err)
}

// Obtain the list of checksumed output descriptors:
descriptors := emergencykit.GetDescriptors(&emergencykit.DescriptorsData{
FirstFingerprint: ekParams.FirstFingerprint,
SecondFingerprint: ekParams.SecondFingerprint,
})

// Create the keys for the key array:
keys := []*emergencykit.MetadataKey{
createEmergencyKitMetadataKey(firstKey),
createEmergencyKitMetadataKey(secondKey),
}

metadata := &emergencykit.Metadata{
Version: 2,
BirthdayBlock: int(secondKey.Birthday),
EncryptedKeys: keys,
OutputDescriptors: descriptors,
}

return metadata, nil
}

func createEmergencyKitMetadataKey(key *encryptedPrivateKey) *emergencykit.MetadataKey {
return &emergencykit.MetadataKey{
DhPubKey: hex.EncodeToString(key.EphPublicKey),
EncryptedPrivKey: hex.EncodeToString(key.CipherText),
Salt: hex.EncodeToString(key.Salt),
}
return &EKOutput{
HTML: out.HTML,
VerificationCode: out.VerificationCode,
}, nil
}
4 changes: 2 additions & 2 deletions emergency_kit_test.go
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (

func TestGenerateEmergencyKitHTML(t *testing.T) {
_, err := GenerateEmergencyKitHTML(&EKInput{
FirstEncryptedKey: "MyFirstEncryptedKey",
SecondEncryptedKey: "MySecondEncryptedKey",
FirstEncryptedKey: "5zZPk5V7oJcXtQyFgdxrP6D5A4Xck2XMC2FG7rrxeDu89K4YuuMoAdZ2MeAGqMU28aR4Lsa5HRxB5mDXmajmYgLaZi6CivXeBRSzazJb8T4VizArrDA8NDH8TipEsHnwCyCd6eiNQYbedyRPw4B",
SecondEncryptedKey: "4RLVcRNPSdCcV5pdd6FsNuUzhGwp3h7piXhpDkHbF31PrHmNqsyMd9vRveXsBVsWPLXHvMkvhzk68yGw4Wwcxfz55yPeN5Jogqpmn7BQc7P1SNymwtgbatLiJfwqFLm1iqoLPobCmK6wH7MY9N7",
}, "es")
if err != nil {
t.Fatal(err)
Expand Down
Loading

0 comments on commit dd796f7

Please sign in to comment.