1 module msgtrans.ee2e.common;
2 
3 import msgtrans.ee2e.crypto;
4 import msgtrans.ee2e.message.MsgDefine;
5 import hunt.logging;
6 import msgtrans.MessageBuffer;
7 import std.string;
8 import google.protobuf;
9 import std.array;
10 import core.stdc.string;
11 import std.base64;
12 
13 class common {
14 
15   static bool keyCalculate(ownkey_s ownkey, peerkey_s peerkey)
16   {
17       ubyte[CRYPTO_SALT_LEN] salt_xor;
18       if (!bytes_xor(ownkey.salt, CRYPTO_SALT_LEN, peerkey.salt, CRYPTO_SALT_LEN, salt_xor))
19       {
20           logError("xor calculation error.");
21           return false;
22       }
23 
24       /* Calculate the shared key using own public and private keys and the public key of the other party */
25       ubyte[CRYPTO_ECDH_SHARED_KEY_LEN] shared_key;
26       if (!calc_ecdh_shared_key(ownkey.ec_pub_key, ownkey.ec_priv_key, peerkey.ec_pub_key, shared_key))
27       {
28           logError("shared key calculation error.");
29           return false;
30       }
31 
32       /* Using HKDF to calculate the final AES key */
33       if (!generate_hkdf_bytes(shared_key, salt_xor, CRYPTO_KEY_INFO.representation, CRYPTO_KEY_INFO.length, peerkey.aes_key))
34       {
35           logError("hkdf calculation error.");
36           return false;
37       }
38 
39       logInfo("Calculated the final AES-KEY: %s",peerkey.aes_key);
40       //dash::hex_dump(peerkey.aes_key, CRYPTO_AES_KEY_LEN, std::cout);
41 
42       return true;
43   }
44 
45   static bool encrypt_plaintext(peerkey_s peerkey, ubyte[] str_plaintext, Ciphertext ciphertext)
46   {
47     ubyte[] str_ciphertext = new ubyte[str_plaintext.length];
48     ubyte[] rand_iv = new ubyte[CRYPTO_AES_IV_LEN];
49     ubyte[] aes_tag = new ubyte[CRYPTO_AES_TAG_LEN];
50 
51 
52     if (!rand_salt(rand_iv, CRYPTO_AES_IV_LEN))
53     {
54         return false;
55     }
56 
57     bool ret = aes_encrypt(str_plaintext.ptr, cast(int)str_plaintext.length, peerkey.aes_key.ptr, rand_iv.ptr, str_ciphertext.ptr, aes_tag.ptr);
58 
59     if (!ret)
60     {
61         return false;
62     }
63 
64 
65     ciphertext.cipher_version = cast(uint)str_plaintext.length;
66     ciphertext.aes_iv_12bytes = Base64.encode(rand_iv);
67     ciphertext.aes_tag_16bytes = Base64.encode(aes_tag);
68     ciphertext.ciphertext_nbytes = Base64.encode(str_ciphertext);
69 
70     logInfo("cipher_version %s",  ciphertext.cipher_version);
71     logInfo("aes_iv_12bytes %s",  rand_iv);
72     logInfo("aes_tag_16bytes %s",  aes_tag);
73     logInfo("ciphertext_nbytes %s",  str_ciphertext);
74     logInfo("aes key:" ,peerkey.aes_key);
75 
76     return true;
77   }
78 
79   static bool generate_token(const ubyte[CRYPTO_EC_PUB_KEY_LEN] ecdh_pub_key, Token token)
80   {
81       ubyte[] random_digit = new ubyte[3];
82       ubyte[] hmac_256 = new ubyte[CRYPTO_HMAC_SHA256];
83 
84 
85       if (!rand_salt(random_digit, 3))
86       {
87           logError("random digit generation error.");
88           return false;
89       }
90 
91       if (!hmac_sha256(hmac_256, random_digit, 3, ecdh_pub_key, CRYPTO_EC_PUB_KEY_LEN))
92       {
93           logError("hmac calculation error.");
94           return false;
95       }
96 
97       token.salt_3bytes = Base64.encode(random_digit);
98       token.hmac_3bytes = Base64.encode(hmac_256);
99 
100       logInfo("token.salt_3bytes  %s",random_digit);
101       logInfo("token.salt_3bytes  %s",token.salt_3bytes);
102       logInfo("token.hmac_3bytes  %s",token.hmac_3bytes);
103 
104       return true;
105   }
106 
107   static bool verify_token(const ubyte[CRYPTO_EC_PUB_KEY_LEN] ecdh_pub_key, Token token)
108   {
109       ubyte[] hmac_256 = new ubyte[CRYPTO_HMAC_SHA256];
110       ubyte[] dd = Base64.decode(token.salt_3bytes);
111 
112     //  logInfo("dd  %s    %d",dd ,cast(uint)token.salt_3bytes.length);
113       bool ret = hmac_sha256(hmac_256, Base64.decode(token.salt_3bytes), 3, ecdh_pub_key, CRYPTO_EC_PUB_KEY_LEN);
114       if (!ret)
115       {
116           logError("hmac calculation error.");
117           return false;
118       }
119 
120       logInfo("hmac_256  %s",hmac_256);
121       logInfo("hmac_3bytes  %s",token.hmac_3bytes);
122       logInfo("salt_3bytes  %s",token.salt_3bytes);
123 
124       if (0 != memcmp(Base64.decode(token.hmac_3bytes).ptr, hmac_256.ptr, 3))
125       {
126           logError("Token check failed");
127           return false;
128       }
129 
130       return true;
131   }
132 
133   static MessageBuffer encrypted_encode(MessageBuffer message ,ownkey_s client_key , peerkey_s server_key)
134   {
135       Ciphertext ciphertext = new Ciphertext;
136       Token token = new Token;
137       token.salt_3bytes = "1";
138       token.hmac_3bytes = "1";
139       EncryptedRequest encrypted_request = new EncryptedRequest;
140       if(!encrypt_plaintext(server_key, message.data, ciphertext))
141       {
142         logError ("aes encryption error.");
143         return null;
144       }
145       if(client_key !is null)
146       {
147         if (!common.generate_token(client_key.ec_pub_key, token))
148         {
149           logError("token generation error.");
150           return null;
151         }
152       }
153       logInfo("out  salt_3bytes  %s",token.salt_3bytes);
154       logInfo("out  hmac_3bytes  %s",token.hmac_3bytes);
155       encrypted_request.token = token;
156       encrypted_request.ciphertext = ciphertext;
157       logInfo("encrypted_request %s",encrypted_request.toProtobuf.array);
158       if (message.hasExtend)
159       {
160         return new MessageBuffer(message.id , encrypted_request.toProtobuf.array, message.extend);
161       }else
162       {
163         return new MessageBuffer(message.id , encrypted_request.toProtobuf.array);
164       }
165   }
166 
167   static MessageBuffer encrypted_decode(MessageBuffer message, peerkey_s peer_key, bool isClient = false)
168   {
169       logInfo("encrypted_decode id: %s" ,message.id);
170       EncryptedRequest encrypted_request = new EncryptedRequest;
171       message.data.fromProtobuf!EncryptedRequest(encrypted_request);
172 
173       if(!isClient)
174       {
175         if (!common.verify_token(peer_key.ec_pub_key, encrypted_request.token))
176         {
177           logError("token check failed.");
178           return null;
179         }
180       }
181 
182       logInfo("============================================================================");
183       logInfo("msgId :%d" , message.id);
184       logInfo("cipher_version %s" , encrypted_request.ciphertext.cipher_version);
185       logInfo("base64 ciphertext_nbytes %s", encrypted_request.ciphertext.ciphertext_nbytes);
186       logInfo("base64 aes_tag_16bytes %s", encrypted_request.ciphertext.aes_tag_16bytes);
187       logInfo("base64 aes_iv_12bytes %s", encrypted_request.ciphertext.aes_iv_12bytes);
188 
189 
190       //uint len = encrypted_request.ciphertext.ciphertext_nbytes.length;
191       uint len = encrypted_request.ciphertext.cipher_version;
192       ubyte[] ciphertext_nbytes = Base64.decode(encrypted_request.ciphertext.ciphertext_nbytes);
193       ubyte[] plaintext = new ubyte[len];
194 
195       logInfo("ciphertext_nbytes %s", ciphertext_nbytes);
196 
197       ubyte[] aes_tag_16bytes = Base64.decode(encrypted_request.ciphertext.aes_tag_16bytes);
198 
199       logInfo("aes_tag_16bytes %s", aes_tag_16bytes);
200       if(len != 0)
201       {
202           bool ret = aes_decrypt(ciphertext_nbytes.ptr,
203           len,
204           aes_tag_16bytes.ptr,
205           peer_key.aes_key.ptr,
206           Base64.decode(encrypted_request.ciphertext.aes_iv_12bytes).ptr, plaintext.ptr);
207           if (!ret)
208           {
209             logError("aes decryption error");
210             return null;
211           }
212       }
213 
214 
215       logInfo("aes_iv_12bytes %s", Base64.decode(encrypted_request.ciphertext.aes_iv_12bytes));
216 
217       logInfo("peer_key.aes_key.ptr  %s" ,peer_key.aes_key);
218 
219 
220       if (message.hasExtend)
221       {
222         return new MessageBuffer(message.id , plaintext,message.extend);
223       }else
224       {
225         return new MessageBuffer(message.id , plaintext);
226       }
227 
228   }
229 
230 }
231