github.com/status-im/status-go@v1.1.0/protocol/encryption/helpers.go (about) 1 package encryption 2 3 import ( 4 "crypto/aes" 5 "crypto/cipher" 6 "crypto/ecdsa" 7 "crypto/rand" 8 "encoding/binary" 9 "errors" 10 "io" 11 "time" 12 13 "github.com/status-im/status-go/eth-node/crypto" 14 "github.com/status-im/status-go/eth-node/crypto/ecies" 15 ) 16 17 const keyBumpValue = uint64(10) 18 19 // GetCurrentTime64 returns the current unix time in milliseconds 20 func GetCurrentTime() uint64 { 21 return (uint64)(time.Now().UnixMilli()) 22 } 23 24 // bumpKeyID takes a timestampID and returns its value incremented by the keyBumpValue 25 func bumpKeyID(timestampID uint64) uint64 { 26 return timestampID + keyBumpValue 27 } 28 29 func generateHashRatchetKeyID(groupID []byte, timestamp uint64, keyBytes []byte) []byte { 30 var keyMaterial []byte 31 32 keyMaterial = append(keyMaterial, groupID...) 33 34 timestampBytes := make([]byte, 8) // 8 bytes for a uint64 35 binary.LittleEndian.PutUint64(timestampBytes, timestamp) 36 keyMaterial = append(keyMaterial, timestampBytes...) 37 38 keyMaterial = append(keyMaterial, keyBytes...) 39 40 return crypto.Keccak256(keyMaterial) 41 } 42 43 func publicKeyMostRelevantBytes(key *ecdsa.PublicKey) uint32 { 44 45 keyBytes := crypto.FromECDSAPub(key) 46 47 return binary.LittleEndian.Uint32(keyBytes[1:5]) 48 } 49 50 func encrypt(plaintext []byte, key []byte, reader io.Reader) ([]byte, error) { 51 c, err := aes.NewCipher(key) 52 if err != nil { 53 return nil, err 54 } 55 56 gcm, err := cipher.NewGCM(c) 57 if err != nil { 58 return nil, err 59 } 60 61 nonce := make([]byte, gcm.NonceSize()) 62 if _, err = io.ReadFull(reader, nonce); err != nil { 63 return nil, err 64 } 65 66 return gcm.Seal(nonce, nonce, plaintext, nil), nil 67 } 68 69 func GenerateSharedKey(privateKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey) ([]byte, error) { 70 71 const encryptedPayloadKeyLength = 16 72 73 return ecies.ImportECDSA(privateKey).GenerateShared( 74 ecies.ImportECDSAPublic(publicKey), 75 encryptedPayloadKeyLength, 76 encryptedPayloadKeyLength, 77 ) 78 } 79 80 func buildGroupRekeyMessage(privateKey *ecdsa.PrivateKey, groupID []byte, timestamp uint64, keyMaterial []byte, keys []*ecdsa.PublicKey) (*RekeyGroup, error) { 81 82 message := &RekeyGroup{ 83 Timestamp: timestamp, 84 } 85 86 message.Keys = make(map[uint32][]byte) 87 88 for _, k := range keys { 89 90 sharedKey, err := GenerateSharedKey(privateKey, k) 91 if err != nil { 92 return nil, err 93 } 94 95 encryptedKey, err := encrypt(keyMaterial, sharedKey, rand.Reader) 96 if err != nil { 97 return nil, err 98 } 99 100 kBytes := publicKeyMostRelevantBytes(k) 101 102 if message.Keys[kBytes] == nil { 103 message.Keys[kBytes] = encryptedKey 104 } else { 105 message.Keys[kBytes] = append(message.Keys[kBytes], encryptedKey...) 106 } 107 } 108 109 return message, nil 110 } 111 112 const nonceLength = 12 113 114 func decrypt(cyphertext []byte, key []byte) ([]byte, error) { 115 if len(cyphertext) < nonceLength { 116 return nil, errors.New("invalid cyphertext length") 117 } 118 119 c, err := aes.NewCipher(key) 120 if err != nil { 121 return nil, err 122 } 123 124 gcm, err := cipher.NewGCM(c) 125 if err != nil { 126 return nil, err 127 } 128 129 nonce := cyphertext[:nonceLength] 130 return gcm.Open(nil, nonce, cyphertext[nonceLength:], nil) 131 } 132 133 const keySize = 60 134 135 func decryptGroupRekeyMessage(privateKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, message *RekeyGroup) ([]byte, error) { 136 kBytes := publicKeyMostRelevantBytes(&privateKey.PublicKey) 137 if message.Keys == nil || message.Keys[kBytes] == nil { 138 return nil, nil 139 } 140 141 sharedKey, err := GenerateSharedKey(privateKey, publicKey) 142 if err != nil { 143 return nil, err 144 } 145 146 keys := message.Keys[kBytes] 147 148 nKeys := len(keys) / keySize 149 150 var decryptedKey []byte 151 for i := 0; i < nKeys; i++ { 152 153 encryptedKey := keys[i*keySize : i*keySize+keySize] 154 decryptedKey, err = decrypt(encryptedKey, sharedKey) 155 if err != nil { 156 continue 157 } else { 158 break 159 } 160 161 } 162 163 return decryptedKey, nil 164 }