Skip to content

Commit 4d4f175

Browse files
committed
Add OpenSSL 1.1.0g support due to hardware acceleration
Note: If you want to compile it by yourself, please make sure do NOT use `no-asm` configure option, since the main point of this commit is to utilize assembly in openssl Add OpenSSL test
1 parent d1219bb commit 4d4f175

15 files changed

+693
-67
lines changed

OPENSSL-GUIDE

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
OpenSSL library guide for VS2017
2+
3+
# Read NOTES.WIN and NOTES.PERL
4+
5+
# use Visual Studio native tools command prompt
6+
# use activeperl, install NASM assembler
7+
ppm install dmake
8+
9+
# Win32 x86
10+
set PATH=D:\NASM-32;%PATH%
11+
perl Configure VC-WIN32 --release --prefix=C:\Users\home\Downloads\openssl-1.1.0g\x86-build --openssldir=C:\Users\home\Downloads\openssl-1.1.0g\x86-install
12+
nmake
13+
nmake test
14+
# to rebuild
15+
nmake distclean

shadowsocks-csharp/Controller/Service/Listener.cs

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public void Start(Configuration config)
8585

8686
// Start an asynchronous socket to listen for connections.
8787
Logging.Info("Shadowsocks started");
88+
Logging.Info(Encryption.EncryptorFactory.DumpRegisteredEncryptor());
8889
_tcpSocket.BeginAccept(new AsyncCallback(AcceptCallback), _tcpSocket);
8990
UDPState udpState = new UDPState();
9091
udpState.socket = _udpSocket;
887 KB
Binary file not shown.

shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ public virtual void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
127127

128128
public static void randBytes(byte[] buf, int length) { RNG.GetBytes(buf, length); }
129129

130-
public abstract int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen);
130+
public abstract void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen);
131131

132-
public abstract int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen);
132+
public abstract void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen);
133133

134134
#region TCP
135135

shadowsocks-csharp/Encryption/AEAD/AEADMbedTLSEncryptor.cs

+9-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public AEADMbedTLSEncryptor(string method, string password)
1919
{
2020
}
2121

22-
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
22+
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
2323
{
2424
{"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)},
2525
{"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)},
@@ -48,6 +48,7 @@ public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
4848
{
4949
_decryptCtx = ctx;
5050
}
51+
5152
MbedTLS.cipher_init(ctx);
5253
if (MbedTLS.cipher_setup(ctx, MbedTLS.cipher_info_from_string(_innerLibName)) != 0)
5354
throw new System.Exception("Cannot initialize mbed TLS cipher context");
@@ -67,7 +68,7 @@ private void CipherSetKey(bool isEncrypt, byte[] key)
6768
if (ret != 0) throw new System.Exception("failed to finish preparation");
6869
}
6970

70-
public override int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
71+
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
7172
{
7273
// buf: all plaintext
7374
// outbuf: ciphertext + tag
@@ -87,18 +88,18 @@ public override int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext
8788
/* cipher */
8889
ciphertext, ref olen,
8990
tagbuf, (uint) tagLen);
90-
if (ret != 0) throw new CryptoErrorException();
91+
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
9192
Debug.Assert(olen == plen);
9293
// attach tag to ciphertext
9394
Array.Copy(tagbuf, 0, ciphertext, (int) plen, tagLen);
9495
clen = olen + (uint) tagLen;
95-
return ret;
96+
break;
9697
default:
9798
throw new System.Exception("not implemented");
9899
}
99100
}
100101

101-
public override int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
102+
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
102103
{
103104
// buf: ciphertext + tag
104105
// outbuf: plaintext
@@ -116,10 +117,10 @@ public override int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext
116117
ciphertext, (uint) (clen - tagLen),
117118
plaintext, ref olen,
118119
tagbuf, (uint) tagLen);
119-
if (ret != 0) throw new CryptoErrorException();
120+
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
120121
Debug.Assert(olen == clen - tagLen);
121122
plen = olen;
122-
return ret;
123+
break;
123124
default:
124125
throw new System.Exception("not implemented");
125126
}
@@ -163,6 +164,7 @@ protected virtual void Dispose(bool disposing)
163164
Marshal.FreeHGlobal(_encryptCtx);
164165
_encryptCtx = IntPtr.Zero;
165166
}
167+
166168
if (_decryptCtx != IntPtr.Zero)
167169
{
168170
MbedTLS.cipher_free(_decryptCtx);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Shadowsocks.Encryption.Exception;
4+
5+
namespace Shadowsocks.Encryption.AEAD
6+
{
7+
public class AEADOpenSSLEncryptor
8+
: AEADEncryptor, IDisposable
9+
{
10+
const int CIPHER_AES = 1;
11+
const int CIPHER_CHACHA20IETFPOLY1305 = 2;
12+
13+
private byte[] _opensslEncSubkey;
14+
private byte[] _opensslDecSubkey;
15+
16+
private IntPtr _encryptCtx = IntPtr.Zero;
17+
private IntPtr _decryptCtx = IntPtr.Zero;
18+
19+
private IntPtr _cipherInfoPtr = IntPtr.Zero;
20+
21+
public AEADOpenSSLEncryptor(string method, string password)
22+
: base(method, password)
23+
{
24+
_opensslEncSubkey = new byte[keyLen];
25+
_opensslDecSubkey = new byte[keyLen];
26+
}
27+
28+
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
29+
{
30+
{"aes-128-gcm", new EncryptorInfo("aes-128-gcm", 16, 16, 12, 16, CIPHER_AES)},
31+
{"aes-192-gcm", new EncryptorInfo("aes-192-gcm", 24, 24, 12, 16, CIPHER_AES)},
32+
{"aes-256-gcm", new EncryptorInfo("aes-256-gcm", 32, 32, 12, 16, CIPHER_AES)},
33+
{"chacha20-ietf-poly1305", new EncryptorInfo("chacha20-poly1305", 32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)}
34+
};
35+
36+
public static List<string> SupportedCiphers()
37+
{
38+
return new List<string>(_ciphers.Keys);
39+
}
40+
41+
protected override Dictionary<string, EncryptorInfo> getCiphers()
42+
{
43+
return _ciphers;
44+
}
45+
46+
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
47+
{
48+
base.InitCipher(salt, isEncrypt, isUdp);
49+
_cipherInfoPtr = OpenSSL.GetCipherInfo(_innerLibName);
50+
if (_cipherInfoPtr == IntPtr.Zero) throw new System.Exception("openssl: cipher not found");
51+
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
52+
if (ctx == IntPtr.Zero) throw new System.Exception("openssl: fail to create ctx");
53+
54+
if (isEncrypt)
55+
{
56+
_encryptCtx = ctx;
57+
}
58+
else
59+
{
60+
_decryptCtx = ctx;
61+
}
62+
63+
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt, _Masterkey,
64+
isEncrypt ? _opensslEncSubkey : _opensslDecSubkey);
65+
66+
var ret = OpenSSL.EVP_CipherInit_ex(ctx, _cipherInfoPtr, IntPtr.Zero, null, null,
67+
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
68+
if (ret != 1) throw new System.Exception("openssl: fail to init ctx");
69+
70+
ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);
71+
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
72+
73+
ret = OpenSSL.EVP_CIPHER_CTX_ctrl(ctx, OpenSSL.EVP_CTRL_AEAD_SET_IVLEN,
74+
nonceLen, IntPtr.Zero);
75+
if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce length");
76+
77+
ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero,
78+
isEncrypt ? _opensslEncSubkey : _opensslDecSubkey,
79+
null,
80+
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
81+
if (ret != 1) throw new System.Exception("openssl: cannot set key");
82+
OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);
83+
}
84+
85+
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
86+
{
87+
OpenSSL.SetCtxNonce(_encryptCtx, _encNonce, true);
88+
// buf: all plaintext
89+
// outbuf: ciphertext + tag
90+
int ret;
91+
int tmpLen = 0;
92+
clen = 0;
93+
var tagBuf = new byte[tagLen];
94+
95+
ret = OpenSSL.EVP_CipherUpdate(_encryptCtx, ciphertext, out tmpLen,
96+
plaintext, (int) plen);
97+
if (ret != 1) throw new CryptoErrorException("openssl: fail to encrypt AEAD");
98+
clen += (uint) tmpLen;
99+
// For AEAD cipher, it should not output anything
100+
ret = OpenSSL.EVP_CipherFinal_ex(_encryptCtx, ciphertext, ref tmpLen);
101+
if (ret != 1) throw new CryptoErrorException("openssl: fail to finalize AEAD");
102+
if (tmpLen > 0)
103+
{
104+
throw new System.Exception("openssl: fail to finish AEAD");
105+
}
106+
107+
OpenSSL.AEADGetTag(_encryptCtx, tagBuf, tagLen);
108+
Array.Copy(tagBuf, 0, ciphertext, clen, tagLen);
109+
clen += (uint) tagLen;
110+
}
111+
112+
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
113+
{
114+
OpenSSL.SetCtxNonce(_decryptCtx, _decNonce, false);
115+
// buf: ciphertext + tag
116+
// outbuf: plaintext
117+
int ret;
118+
int tmpLen = 0;
119+
plen = 0;
120+
121+
// split tag
122+
byte[] tagbuf = new byte[tagLen];
123+
Array.Copy(ciphertext, (int) (clen - tagLen), tagbuf, 0, tagLen);
124+
OpenSSL.AEADSetTag(_decryptCtx, tagbuf, tagLen);
125+
126+
ret = OpenSSL.EVP_CipherUpdate(_decryptCtx,
127+
plaintext, out tmpLen, ciphertext, (int) (clen - tagLen));
128+
if (ret != 1) throw new CryptoErrorException("openssl: fail to decrypt AEAD");
129+
plen += (uint) tmpLen;
130+
131+
// For AEAD cipher, it should not output anything
132+
ret = OpenSSL.EVP_CipherFinal_ex(_decryptCtx, plaintext, ref tmpLen);
133+
if (ret <= 0)
134+
{
135+
// If this is not successful authenticated
136+
throw new CryptoErrorException(String.Format("ret is {0}", ret));
137+
}
138+
139+
if (tmpLen > 0)
140+
{
141+
throw new System.Exception("openssl: fail to finish AEAD");
142+
}
143+
}
144+
145+
#region IDisposable
146+
147+
private bool _disposed;
148+
149+
// instance based lock
150+
private readonly object _lock = new object();
151+
152+
public override void Dispose()
153+
{
154+
Dispose(true);
155+
GC.SuppressFinalize(this);
156+
}
157+
158+
~AEADOpenSSLEncryptor()
159+
{
160+
Dispose(false);
161+
}
162+
163+
protected virtual void Dispose(bool disposing)
164+
{
165+
lock (_lock)
166+
{
167+
if (_disposed) return;
168+
_disposed = true;
169+
}
170+
171+
if (disposing)
172+
{
173+
// free managed objects
174+
}
175+
176+
// free unmanaged objects
177+
if (_encryptCtx != IntPtr.Zero)
178+
{
179+
OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);
180+
_encryptCtx = IntPtr.Zero;
181+
}
182+
183+
if (_decryptCtx != IntPtr.Zero)
184+
{
185+
OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);
186+
_decryptCtx = IntPtr.Zero;
187+
}
188+
}
189+
190+
#endregion
191+
}
192+
}

shadowsocks-csharp/Encryption/AEAD/AEADSodiumEncryptor.cs

+5-7
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public AEADSodiumEncryptor(string method, string password)
2222
_sodiumDecSubkey = new byte[keyLen];
2323
}
2424

25-
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
25+
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
2626
{
2727
{"chacha20-ietf-poly1305", new EncryptorInfo(32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)},
2828
{"aes-256-gcm", new EncryptorInfo(32, 32, 12, 16, CIPHER_AES256GCM)},
@@ -46,7 +46,7 @@ public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
4646
}
4747

4848

49-
public override int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
49+
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
5050
{
5151
Debug.Assert(_sodiumEncSubkey != null);
5252
// buf: all plaintext
@@ -75,13 +75,12 @@ public override int cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext
7575
default:
7676
throw new System.Exception("not implemented");
7777
}
78-
if (ret != 0) throw new CryptoErrorException();
78+
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
7979
Logging.Dump("after cipherEncrypt: cipher", ciphertext, (int) encClen);
8080
clen = (uint) encClen;
81-
return ret;
8281
}
8382

84-
public override int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
83+
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
8584
{
8685
Debug.Assert(_sodiumDecSubkey != null);
8786
// buf: ciphertext + tag
@@ -111,10 +110,9 @@ public override int cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext
111110
throw new System.Exception("not implemented");
112111
}
113112

114-
if (ret != 0) throw new CryptoErrorException();
113+
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
115114
Logging.Dump("after cipherDecrypt: plain", plaintext, (int) decPlen);
116115
plen = (uint) decPlen;
117-
return ret;
118116
}
119117

120118
public override void Dispose()

0 commit comments

Comments
 (0)