You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

IVEncryptor.cs 11 kB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Concurrent;
  4. using System.Linq;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.Net;
  8. namespace Shadowsocks.Encryption
  9. {
  10. public abstract class IVEncryptor
  11. : EncryptorBase
  12. {
  13. public const int MAX_KEY_LENGTH = 64;
  14. public const int MAX_IV_LENGTH = 16;
  15. protected static byte[] tempbuf = new byte[MAX_INPUT_SIZE];
  16. protected Dictionary<string, EncryptorInfo> ciphers;
  17. private static readonly ConcurrentDictionary<string, byte[]> CachedKeys = new ConcurrentDictionary<string, byte[]>();
  18. protected byte[] _encryptIV;
  19. protected byte[] _decryptIV;
  20. protected bool _decryptIVReceived;
  21. protected bool _encryptIVSent;
  22. protected string _method;
  23. protected int _cipher;
  24. // internal name in the crypto library
  25. protected string _innerLibName;
  26. protected EncryptorInfo CipherInfo;
  27. protected byte[] _key;
  28. protected int keyLen;
  29. protected int ivLen;
  30. public IVEncryptor(string method, string password, bool onetimeauth, bool isudp)
  31. : base(method, password, onetimeauth, isudp)
  32. {
  33. InitKey(method, password);
  34. }
  35. protected abstract Dictionary<string, EncryptorInfo> getCiphers();
  36. private void InitKey(string method, string password)
  37. {
  38. method = method.ToLower();
  39. _method = method;
  40. string k = method + ":" + password;
  41. ciphers = getCiphers();
  42. CipherInfo = ciphers[_method];
  43. _innerLibName = CipherInfo.InnerLibName;
  44. _cipher = CipherInfo.Type;
  45. if (_cipher == 0)
  46. {
  47. throw new Exception("method not found");
  48. }
  49. keyLen = CipherInfo.KeySize;
  50. ivLen = CipherInfo.IvSize;
  51. _key = CachedKeys.GetOrAdd(k, (nk) =>
  52. {
  53. byte[] passbuf = Encoding.UTF8.GetBytes(password);
  54. byte[] key = new byte[32];
  55. bytesToKey(passbuf, key);
  56. return key;
  57. });
  58. }
  59. protected void bytesToKey(byte[] password, byte[] key)
  60. {
  61. byte[] result = new byte[password.Length + 16];
  62. int i = 0;
  63. byte[] md5sum = null;
  64. while (i < key.Length)
  65. {
  66. if (i == 0)
  67. {
  68. md5sum = MbedTLS.MD5(password);
  69. }
  70. else
  71. {
  72. md5sum.CopyTo(result, 0);
  73. password.CopyTo(result, md5sum.Length);
  74. md5sum = MbedTLS.MD5(result);
  75. }
  76. md5sum.CopyTo(key, i);
  77. i += md5sum.Length;
  78. }
  79. }
  80. protected virtual void initCipher(byte[] iv, bool isCipher)
  81. {
  82. if (ivLen > 0)
  83. {
  84. if (isCipher)
  85. {
  86. _encryptIV = new byte[ivLen];
  87. Array.Copy(iv, _encryptIV, ivLen);
  88. }
  89. else
  90. {
  91. _decryptIV = new byte[ivLen];
  92. Array.Copy(iv, _decryptIV, ivLen);
  93. }
  94. }
  95. }
  96. protected abstract void cipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf);
  97. #region OneTimeAuth
  98. public const int ONETIMEAUTH_FLAG = 0x10;
  99. public const int ADDRTYPE_MASK = 0xF;
  100. public const int ONETIMEAUTH_BYTES = 10;
  101. public const int CLEN_BYTES = 2;
  102. public const int AUTH_BYTES = ONETIMEAUTH_BYTES + CLEN_BYTES;
  103. private uint _otaChunkCounter;
  104. private byte[] _otaChunkKeyBuffer;
  105. protected int OtaGetHeadLen(byte[] buf, int length)
  106. {
  107. int len = 0;
  108. int atyp = length > 0 ? (buf[0] & ADDRTYPE_MASK) : 0;
  109. if (atyp == 1)
  110. {
  111. len = 7; // atyp (1 bytes) + ipv4 (4 bytes) + port (2 bytes)
  112. }
  113. else if (atyp == 3 && length > 1)
  114. {
  115. int nameLen = buf[1];
  116. len = 4 + nameLen; // atyp (1 bytes) + name length (1 bytes) + name (n bytes) + port (2 bytes)
  117. }
  118. else if (atyp == 4)
  119. {
  120. len = 19; // atyp (1 bytes) + ipv6 (16 bytes) + port (2 bytes)
  121. }
  122. if (len == 0 || len > length)
  123. throw new Exception($"invalid header with addr type {atyp}");
  124. return len;
  125. }
  126. private byte[] OtaGenHash(byte[] msg, int msg_len)
  127. {
  128. byte[] auth = new byte[ONETIMEAUTH_BYTES];
  129. byte[] hash = new byte[20];
  130. byte[] auth_key = new byte[MAX_IV_LENGTH + MAX_KEY_LENGTH];
  131. Buffer.BlockCopy(_encryptIV, 0, auth_key, 0, ivLen);
  132. Buffer.BlockCopy(_key, 0, auth_key, ivLen, keyLen);
  133. Sodium.ss_sha1_hmac_ex(auth_key, (uint)(ivLen + keyLen),
  134. msg, 0, (uint)msg_len, hash);
  135. Buffer.BlockCopy(hash, 0, auth, 0, ONETIMEAUTH_BYTES);
  136. return auth;
  137. }
  138. private void OtaUpdateKeyBuffer()
  139. {
  140. if (_otaChunkKeyBuffer == null)
  141. {
  142. _otaChunkKeyBuffer = new byte[MAX_IV_LENGTH + 4];
  143. Buffer.BlockCopy(_encryptIV, 0, _otaChunkKeyBuffer, 0, ivLen);
  144. }
  145. byte[] counter_bytes = BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder((int)_otaChunkCounter));
  146. Buffer.BlockCopy(counter_bytes, 0, _otaChunkKeyBuffer, ivLen, 4);
  147. _otaChunkCounter++;
  148. }
  149. private byte[] OtaGenChunkHash(byte[] buf, int offset, int len)
  150. {
  151. byte[] hash = new byte[20];
  152. OtaUpdateKeyBuffer();
  153. Sodium.ss_sha1_hmac_ex(_otaChunkKeyBuffer, (uint)_otaChunkKeyBuffer.Length,
  154. buf, offset, (uint)len, hash);
  155. return hash;
  156. }
  157. private void OtaAuthBuffer4Tcp(byte[] buf, ref int length)
  158. {
  159. if (!_encryptIVSent)
  160. {
  161. int headLen = OtaGetHeadLen(buf, length);
  162. int dataLen = length - headLen;
  163. buf[0] |= ONETIMEAUTH_FLAG;
  164. byte[] hash = OtaGenHash(buf, headLen);
  165. Buffer.BlockCopy(buf, headLen, buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen);
  166. Buffer.BlockCopy(hash, 0, buf, headLen, ONETIMEAUTH_BYTES);
  167. if (dataLen == 0)
  168. {
  169. length = headLen + ONETIMEAUTH_BYTES;
  170. }
  171. else
  172. {
  173. hash = OtaGenChunkHash(buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen);
  174. Buffer.BlockCopy(hash, 0, buf, headLen + ONETIMEAUTH_BYTES + CLEN_BYTES, ONETIMEAUTH_BYTES);
  175. byte[] lenBytes = BitConverter.GetBytes((ushort) IPAddress.HostToNetworkOrder((short) dataLen));
  176. Buffer.BlockCopy(lenBytes, 0, buf, headLen + ONETIMEAUTH_BYTES, CLEN_BYTES);
  177. length = headLen + ONETIMEAUTH_BYTES + AUTH_BYTES + dataLen;
  178. }
  179. }
  180. else
  181. {
  182. byte[] hash = OtaGenChunkHash(buf, 0, length);
  183. Buffer.BlockCopy(buf, 0, buf, AUTH_BYTES, length);
  184. byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)length));
  185. Buffer.BlockCopy(lenBytes, 0, buf, 0, CLEN_BYTES);
  186. Buffer.BlockCopy(hash, 0, buf, CLEN_BYTES, ONETIMEAUTH_BYTES);
  187. length += AUTH_BYTES;
  188. }
  189. }
  190. private void OtaAuthBuffer4Udp(byte[] buf, ref int length)
  191. {
  192. buf[0] |= ONETIMEAUTH_FLAG;
  193. byte[] hash = OtaGenHash(buf, length);
  194. Buffer.BlockCopy(hash, 0, buf, length, ONETIMEAUTH_BYTES);
  195. length += ONETIMEAUTH_BYTES;
  196. }
  197. private void OtaAuthBuffer(byte[] buf, ref int length)
  198. {
  199. if (OnetimeAuth && ivLen > 0)
  200. {
  201. if (!IsUDP)
  202. {
  203. OtaAuthBuffer4Tcp(buf, ref length);
  204. }
  205. else
  206. {
  207. OtaAuthBuffer4Udp(buf, ref length);
  208. }
  209. }
  210. }
  211. #endregion
  212. protected static void randBytes(byte[] buf, int length)
  213. {
  214. byte[] temp = new byte[length];
  215. RNGCryptoServiceProvider rngServiceProvider = new RNGCryptoServiceProvider();
  216. rngServiceProvider.GetBytes(temp);
  217. temp.CopyTo(buf, 0);
  218. }
  219. public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  220. {
  221. if (!_encryptIVSent)
  222. {
  223. // Generate IV
  224. randBytes(outbuf, ivLen);
  225. initCipher(outbuf, true);
  226. outlength = length + ivLen;
  227. OtaAuthBuffer(buf, ref length);
  228. _encryptIVSent = true;
  229. lock (tempbuf)
  230. {
  231. cipherUpdate(true, length, buf, tempbuf);
  232. outlength = length + ivLen;
  233. Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, length);
  234. }
  235. }
  236. else
  237. {
  238. OtaAuthBuffer(buf, ref length);
  239. outlength = length;
  240. cipherUpdate(true, length, buf, outbuf);
  241. }
  242. }
  243. public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
  244. {
  245. if (!_decryptIVReceived)
  246. {
  247. _decryptIVReceived = true;
  248. initCipher(buf, false);
  249. outlength = length - ivLen;
  250. lock (tempbuf)
  251. {
  252. // C# could be multi-threaded
  253. Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen);
  254. cipherUpdate(false, length - ivLen, tempbuf, outbuf);
  255. }
  256. }
  257. else
  258. {
  259. outlength = length;
  260. cipherUpdate(false, length, buf, outbuf);
  261. }
  262. }
  263. }
  264. }