-
Notifications
You must be signed in to change notification settings - Fork 205
/
AesGcm.cs
136 lines (97 loc) · 5.28 KB
/
AesGcm.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace BrowserGhost
{
//AES GCM from https://github.com/dvsekhvalnov/jose-jwt
class AesGcm
{
public byte[] Decrypt(byte[] key, byte[] iv, byte[] aad, byte[] cipherText, byte[] authTag)
{
IntPtr hAlg = OpenAlgorithmProvider(BCrypt.BCRYPT_AES_ALGORITHM, BCrypt.MS_PRIMITIVE_PROVIDER, BCrypt.BCRYPT_CHAIN_MODE_GCM);
IntPtr hKey, keyDataBuffer = ImportKey(hAlg, key, out hKey);
byte[] plainText;
var authInfo = new BCrypt.BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(iv, aad, authTag);
using (authInfo)
{
byte[] ivData = new byte[MaxAuthTagSize(hAlg)];
int plainTextSize = 0;
uint status = BCrypt.BCryptDecrypt(hKey, cipherText, cipherText.Length, ref authInfo, ivData, ivData.Length, null, 0, ref plainTextSize, 0x0);
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptDecrypt() (get size) failed with status code: {0}", status));
plainText = new byte[plainTextSize];
status = BCrypt.BCryptDecrypt(hKey, cipherText, cipherText.Length, ref authInfo, ivData, ivData.Length, plainText, plainText.Length, ref plainTextSize, 0x0);
if (status == BCrypt.STATUS_AUTH_TAG_MISMATCH)
throw new CryptographicException("BCrypt.BCryptDecrypt(): authentication tag mismatch");
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptDecrypt() failed with status code:{0}", status));
}
BCrypt.BCryptDestroyKey(hKey);
Marshal.FreeHGlobal(keyDataBuffer);
BCrypt.BCryptCloseAlgorithmProvider(hAlg, 0x0);
return plainText;
}
private int MaxAuthTagSize(IntPtr hAlg)
{
byte[] tagLengthsValue = GetProperty(hAlg, BCrypt.BCRYPT_AUTH_TAG_LENGTH);
return BitConverter.ToInt32(new[] { tagLengthsValue[4], tagLengthsValue[5], tagLengthsValue[6], tagLengthsValue[7] }, 0);
}
private IntPtr OpenAlgorithmProvider(string alg, string provider, string chainingMode)
{
IntPtr hAlg = IntPtr.Zero;
uint status = BCrypt.BCryptOpenAlgorithmProvider(out hAlg, alg, provider, 0x0);
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptOpenAlgorithmProvider() failed with status code:{0}", status));
byte[] chainMode = Encoding.Unicode.GetBytes(chainingMode);
status = BCrypt.BCryptSetAlgorithmProperty(hAlg, BCrypt.BCRYPT_CHAINING_MODE, chainMode, chainMode.Length, 0x0);
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptSetAlgorithmProperty(BCrypt.BCRYPT_CHAINING_MODE, BCrypt.BCRYPT_CHAIN_MODE_GCM) failed with status code:{0}", status));
return hAlg;
}
private IntPtr ImportKey(IntPtr hAlg, byte[] key, out IntPtr hKey)
{
byte[] objLength = GetProperty(hAlg, BCrypt.BCRYPT_OBJECT_LENGTH);
int keyDataSize = BitConverter.ToInt32(objLength, 0);
IntPtr keyDataBuffer = Marshal.AllocHGlobal(keyDataSize);
byte[] keyBlob = Concat(BCrypt.BCRYPT_KEY_DATA_BLOB_MAGIC, BitConverter.GetBytes(0x1), BitConverter.GetBytes(key.Length), key);
uint status = BCrypt.BCryptImportKey(hAlg, IntPtr.Zero, BCrypt.BCRYPT_KEY_DATA_BLOB, out hKey, keyDataBuffer, keyDataSize, keyBlob, keyBlob.Length, 0x0);
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptImportKey() failed with status code:{0}", status));
return keyDataBuffer;
}
private byte[] GetProperty(IntPtr hAlg, string name)
{
int size = 0;
uint status = BCrypt.BCryptGetProperty(hAlg, name, null, 0, ref size, 0x0);
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptGetProperty() (get size) failed with status code:{0}", status));
byte[] value = new byte[size];
status = BCrypt.BCryptGetProperty(hAlg, name, value, value.Length, ref size, 0x0);
if (status != BCrypt.ERROR_SUCCESS)
throw new CryptographicException(string.Format("BCrypt.BCryptGetProperty() failed with status code:{0}", status));
return value;
}
public byte[] Concat(params byte[][] arrays)
{
int len = 0;
foreach (byte[] array in arrays)
{
if (array == null)
continue;
len += array.Length;
}
byte[] result = new byte[len - 1 + 1];
int offset = 0;
foreach (byte[] array in arrays)
{
if (array == null)
continue;
Buffer.BlockCopy(array, 0, result, offset, array.Length);
offset += array.Length;
}
return result;
}
}
}