github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/packer/legacy/anoncrypt/unpack.go (about) 1 /* 2 Copyright Avast Software. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package anoncryt 8 9 import ( 10 "encoding/base64" 11 "encoding/json" 12 "fmt" 13 14 "github.com/btcsuite/btcutil/base58" 15 chacha "golang.org/x/crypto/chacha20poly1305" 16 17 "github.com/hyperledger/aries-framework-go/pkg/doc/util/jwkkid" 18 19 "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" 20 "github.com/hyperledger/aries-framework-go/pkg/kms" 21 ) 22 23 // Unpack will decode the envelope using the legacy format 24 // Using (X)Chacha20 encryption algorithm and Poly1035 authenticator. 25 func (p *Packer) Unpack(envelope []byte) (*transport.Envelope, error) { 26 var envelopeData legacyEnvelope 27 28 err := json.Unmarshal(envelope, &envelopeData) 29 if err != nil { 30 return nil, err 31 } 32 33 protectedBytes, err := base64.URLEncoding.DecodeString(envelopeData.Protected) 34 if err != nil { 35 return nil, err 36 } 37 38 var protectedData protected 39 40 err = json.Unmarshal(protectedBytes, &protectedData) 41 if err != nil { 42 return nil, err 43 } 44 45 if protectedData.Typ != encodingType { 46 return nil, fmt.Errorf("message type %s not supported", protectedData.Typ) 47 } 48 49 if protectedData.Alg != anonCrypt { 50 return nil, fmt.Errorf("message format %s not supported", protectedData.Alg) 51 } 52 53 keys, err := getCEK(protectedData.Recipients, p.kms) 54 if err != nil { 55 return nil, err 56 } 57 58 cek, recKey := keys.cek, keys.myKey 59 60 data, err := p.decodeCipherText(cek, &envelopeData) 61 62 return &transport.Envelope{ 63 Message: data, 64 ToKey: recKey, 65 }, err 66 } 67 68 type keys struct { 69 cek *[chacha.KeySize]byte 70 myKey []byte 71 } 72 73 func getCEK(recipients []recipient, km kms.KeyManager) (*keys, error) { 74 var candidateKeys []string 75 76 for _, candidate := range recipients { 77 candidateKeys = append(candidateKeys, candidate.Header.KID) 78 } 79 80 recKeyIdx, err := findVerKey(km, candidateKeys) 81 if err != nil { 82 return nil, fmt.Errorf("getCEK: no key accessible %w", err) 83 } 84 85 recip := recipients[recKeyIdx] 86 recKey := base58.Decode(recip.Header.KID) 87 88 encCEK, err := base64.URLEncoding.DecodeString(recip.EncryptedKey) 89 if err != nil { 90 return nil, err 91 } 92 93 b, err := newCryptoBox(km) 94 if err != nil { 95 return nil, err 96 } 97 98 cekSlice, err := b.SealOpen(encCEK, recKey) 99 if err != nil { 100 return nil, fmt.Errorf("failed to decrypt CEK: %w", err) 101 } 102 103 var cek [chacha.KeySize]byte 104 105 copy(cek[:], cekSlice) 106 107 return &keys{ 108 cek: &cek, 109 myKey: recKey, 110 }, nil 111 } 112 113 func findVerKey(km kms.KeyManager, candidateKeys []string) (int, error) { 114 var errs []error 115 116 for i, key := range candidateKeys { 117 recKID, err := jwkkid.CreateKID(base58.Decode(key), kms.ED25519Type) 118 if err != nil { 119 return -1, err 120 } 121 122 _, err = km.Get(recKID) 123 if err == nil { 124 return i, nil 125 } 126 127 errs = append(errs, err) 128 } 129 130 return -1, fmt.Errorf("none of the recipient keys were found in kms: %v", errs) 131 } 132 133 // decodeCipherText decodes (from base64) and decrypts the ciphertext using chacha20poly1305. 134 func (p *Packer) decodeCipherText(cek *[chacha.KeySize]byte, envelope *legacyEnvelope) ([]byte, error) { 135 var cipherText, nonce, tag, aad, message []byte 136 aad = []byte(envelope.Protected) 137 138 cipherText, err := base64.URLEncoding.DecodeString(envelope.CipherText) 139 if err != nil { 140 return nil, fmt.Errorf("decodeCipherText: failed to decode b64Sender: %w", err) 141 } 142 143 nonce, err = base64.URLEncoding.DecodeString(envelope.IV) 144 if err != nil { 145 return nil, err 146 } 147 148 tag, err = base64.URLEncoding.DecodeString(envelope.Tag) 149 if err != nil { 150 return nil, err 151 } 152 153 chachaCipher, err := chacha.New(cek[:]) 154 if err != nil { 155 return nil, err 156 } 157 158 payload := append(cipherText, tag...) 159 160 message, err = chachaCipher.Open(nil, nonce, payload, aad) 161 if err != nil { 162 return nil, err 163 } 164 165 return message, nil 166 }