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.

AEADSodiumEncryptor.cs 5.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using NLog;
  5. using Shadowsocks.Controller;
  6. using Shadowsocks.Encryption.Exception;
  7. namespace Shadowsocks.Encryption.AEAD
  8. {
  9. public class AEADSodiumEncryptor
  10. : AEADEncryptor, IDisposable
  11. {
  12. private static Logger logger = LogManager.GetCurrentClassLogger();
  13. private const int CIPHER_CHACHA20IETFPOLY1305 = 1;
  14. private const int CIPHER_XCHACHA20IETFPOLY1305 = 2;
  15. private const int CIPHER_AES256GCM = 3;
  16. private byte[] _sodiumEncSubkey;
  17. private byte[] _sodiumDecSubkey;
  18. public AEADSodiumEncryptor(string method, string password)
  19. : base(method, password)
  20. {
  21. _sodiumEncSubkey = new byte[keyLen];
  22. _sodiumDecSubkey = new byte[keyLen];
  23. }
  24. private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
  25. {
  26. {"chacha20-ietf-poly1305", new EncryptorInfo(32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)},
  27. {"xchacha20-ietf-poly1305", new EncryptorInfo(32, 32, 24, 16, CIPHER_XCHACHA20IETFPOLY1305)},
  28. {"aes-256-gcm", new EncryptorInfo(32, 32, 12, 16, CIPHER_AES256GCM)},
  29. };
  30. public static List<string> SupportedCiphers()
  31. {
  32. return new List<string>(_ciphers.Keys);
  33. }
  34. protected override Dictionary<string, EncryptorInfo> getCiphers()
  35. {
  36. return _ciphers;
  37. }
  38. public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
  39. {
  40. base.InitCipher(salt, isEncrypt, isUdp);
  41. DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt, _Masterkey,
  42. isEncrypt ? _sodiumEncSubkey : _sodiumDecSubkey);
  43. }
  44. public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
  45. {
  46. Debug.Assert(_sodiumEncSubkey != null);
  47. // buf: all plaintext
  48. // outbuf: ciphertext + tag
  49. int ret;
  50. ulong encClen = 0;
  51. logger.Dump("_encNonce before enc", _encNonce, nonceLen);
  52. logger.Dump("_sodiumEncSubkey", _sodiumEncSubkey, keyLen);
  53. logger.Dump("before cipherEncrypt: plain", plaintext, (int) plen);
  54. switch (_cipher)
  55. {
  56. case CIPHER_CHACHA20IETFPOLY1305:
  57. ret = Sodium.crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext, ref encClen,
  58. plaintext, (ulong) plen,
  59. null, 0,
  60. null, _encNonce,
  61. _sodiumEncSubkey);
  62. break;
  63. case CIPHER_XCHACHA20IETFPOLY1305:
  64. ret = Sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(ciphertext, ref encClen,
  65. plaintext, (ulong)plen,
  66. null, 0,
  67. null, _encNonce,
  68. _sodiumEncSubkey);
  69. break;
  70. case CIPHER_AES256GCM:
  71. ret = Sodium.crypto_aead_aes256gcm_encrypt(ciphertext, ref encClen,
  72. plaintext, (ulong)plen,
  73. null, 0,
  74. null, _encNonce,
  75. _sodiumEncSubkey);
  76. break;
  77. default:
  78. throw new System.Exception("not implemented");
  79. }
  80. if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
  81. logger.Dump("after cipherEncrypt: cipher", ciphertext, (int) encClen);
  82. clen = (uint) encClen;
  83. }
  84. public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
  85. {
  86. Debug.Assert(_sodiumDecSubkey != null);
  87. // buf: ciphertext + tag
  88. // outbuf: plaintext
  89. int ret;
  90. ulong decPlen = 0;
  91. logger.Dump("_decNonce before dec", _decNonce, nonceLen);
  92. logger.Dump("_sodiumDecSubkey", _sodiumDecSubkey, keyLen);
  93. logger.Dump("before cipherDecrypt: cipher", ciphertext, (int) clen);
  94. switch (_cipher)
  95. {
  96. case CIPHER_CHACHA20IETFPOLY1305:
  97. ret = Sodium.crypto_aead_chacha20poly1305_ietf_decrypt(plaintext, ref decPlen,
  98. null,
  99. ciphertext, (ulong) clen,
  100. null, 0,
  101. _decNonce, _sodiumDecSubkey);
  102. break;
  103. case CIPHER_XCHACHA20IETFPOLY1305:
  104. ret = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(plaintext, ref decPlen,
  105. null,
  106. ciphertext, (ulong)clen,
  107. null, 0,
  108. _decNonce, _sodiumDecSubkey);
  109. break;
  110. case CIPHER_AES256GCM:
  111. ret = Sodium.crypto_aead_aes256gcm_decrypt(plaintext, ref decPlen,
  112. null,
  113. ciphertext, (ulong)clen,
  114. null, 0,
  115. _decNonce, _sodiumDecSubkey);
  116. break;
  117. default:
  118. throw new System.Exception("not implemented");
  119. }
  120. if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
  121. logger.Dump("after cipherDecrypt: plain", plaintext, (int) decPlen);
  122. plen = (uint) decPlen;
  123. }
  124. public override void Dispose()
  125. {
  126. }
  127. }
  128. }