├── Hydrogen.cs ├── LICENSE └── README.md /Hydrogen.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Managed C# wrapper for Hydrogen cryptographic library by Frank Denis 3 | * Copyright (c) 2018 Stanislav Denisov 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | */ 23 | 24 | using System; 25 | using System.Runtime.CompilerServices; 26 | using System.Runtime.InteropServices; 27 | using System.Security; 28 | 29 | namespace Hydrogen { 30 | [StructLayout(LayoutKind.Sequential)] 31 | public struct KeyPair { 32 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 33 | public byte[] publicKey; 34 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 35 | public byte[] secretKey; 36 | } 37 | 38 | [StructLayout(LayoutKind.Sequential)] 39 | public struct SessionKeyPair { 40 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 41 | public byte[] receiveKey; 42 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 43 | public byte[] sendKey; 44 | } 45 | 46 | [StructLayout(LayoutKind.Sequential)] 47 | public struct HashState { 48 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] 49 | private uint[] state; 50 | private byte offset; 51 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 52 | private byte[] align; 53 | } 54 | 55 | [StructLayout(LayoutKind.Sequential)] 56 | public struct KeyState { 57 | private KeyPair ephemeralKeyPair; 58 | private HashState hashState; 59 | } 60 | 61 | [StructLayout(LayoutKind.Sequential)] 62 | public struct SignKeyPair { 63 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 64 | public byte[] publicKey; 65 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] 66 | public byte[] secretKey; 67 | } 68 | 69 | [StructLayout(LayoutKind.Sequential)] 70 | public struct SignState { 71 | private HashState hashState; 72 | } 73 | 74 | public static class Library { 75 | public const int hashKeyBytes = 32; 76 | public const int hashBytesMin = 16; 77 | public const int hashBytesMax = 65535; 78 | public const int masterKeyBytes = 32; 79 | public const int storedBytes = 128; 80 | public const int headerBytes = 20 + 16; 81 | public const int secretKeyBytes = 32; 82 | public const int probeBytes = 16; 83 | public const int packetBytes = 32 + 16; 84 | public const int signPublicKeyBytes = 32; 85 | public const int signSecretKeyBytes = 64; 86 | public const int signBytes = 64; 87 | 88 | public static bool Initialize() { 89 | return Native.hydro_init() == 0; 90 | } 91 | 92 | [MethodImpl(256)] 93 | public static uint Random() { 94 | return Random(0); 95 | } 96 | 97 | [MethodImpl(256)] 98 | public static uint Random(uint upperBound) { 99 | if (upperBound > 0) 100 | return Native.hydro_random_uniform(upperBound); 101 | 102 | return Native.hydro_random_u32(); 103 | } 104 | 105 | [MethodImpl(256)] 106 | public static void HashKeygen(byte[] key) { 107 | if (key.Length != Library.hashKeyBytes) 108 | throw new ArgumentOutOfRangeException(); 109 | 110 | Native.hydro_hash_keygen(key); 111 | } 112 | 113 | [MethodImpl(256)] 114 | public static bool Hash(byte[] hash, int hashLength, byte[] message, int messageLength, string context) { 115 | if (hashLength < 0 || messageLength < 0 || hashLength < Library.hashBytesMin || hashLength > Library.hashBytesMax) 116 | throw new ArgumentOutOfRangeException(); 117 | 118 | return Native.hydro_hash_hash(hash, (IntPtr)hashLength, message, (IntPtr)messageLength, context, IntPtr.Zero) == 0; 119 | } 120 | 121 | [MethodImpl(256)] 122 | public static bool Hash(byte[] hash, int hashLength, byte[] message, int messageLength, string context, byte[] key) { 123 | if (hashLength < 0 || messageLength < 0 || hashLength < Library.hashBytesMin || hashLength > Library.hashBytesMax) 124 | throw new ArgumentOutOfRangeException(); 125 | 126 | return Native.hydro_hash_hash(hash, (IntPtr)hashLength, message, (IntPtr)messageLength, context, key) == 0; 127 | } 128 | 129 | [MethodImpl(256)] 130 | public static void MasterKeygen(byte[] key) { 131 | if (key.Length != Library.masterKeyBytes) 132 | throw new ArgumentOutOfRangeException(); 133 | 134 | Native.hydro_pwhash_keygen(key); 135 | } 136 | 137 | [MethodImpl(256)] 138 | public static bool DeterministicKey(byte[] key, int keyLength, string password, int passwordLength, string context, byte[] masterKey, ulong iterationsLimit, int memoryLimit, byte threads) { 139 | if (keyLength < 0 || passwordLength < 0 || memoryLimit < 0) 140 | throw new ArgumentOutOfRangeException(); 141 | 142 | return Native.hydro_pwhash_deterministic(key, (IntPtr)keyLength, password, (IntPtr)passwordLength, context, masterKey, iterationsLimit, (IntPtr)memoryLimit, threads) == 0; 143 | } 144 | 145 | [MethodImpl(256)] 146 | public static bool StorageKey(byte[] key, string password, int passwordLength, byte[] masterKey, ulong iterationsLimit, int memoryLimit, byte threads) { 147 | if (passwordLength < 0 || memoryLimit < 0 || key.Length != Library.storedBytes) 148 | throw new ArgumentOutOfRangeException(); 149 | 150 | return Native.hydro_pwhash_create(key, password, (IntPtr)passwordLength, masterKey, iterationsLimit, (IntPtr)memoryLimit, threads) == 0; 151 | } 152 | 153 | [MethodImpl(256)] 154 | public static bool VerifyKey(byte[] key, string password, int passwordLength, byte[] masterKey, ulong iterationsLimit, int memoryLimit, byte threads) { 155 | if (passwordLength < 0 || memoryLimit < 0) 156 | throw new ArgumentOutOfRangeException(); 157 | 158 | return Native.hydro_pwhash_verify(key, password, (IntPtr)passwordLength, masterKey, iterationsLimit, (IntPtr)memoryLimit, threads) == 0; 159 | } 160 | 161 | [MethodImpl(256)] 162 | public static bool ReencryptKey(byte[] key, byte[] masterKey, byte[] newMasterKey) { 163 | return Native.hydro_pwhash_reencrypt(key, masterKey, newMasterKey) == 0; 164 | } 165 | 166 | [MethodImpl(256)] 167 | public static bool UpgradeKey(byte[] key, byte[] masterKey, ulong iterationsLimit, int memoryLimit, byte threads) { 168 | if (memoryLimit < 0) 169 | throw new ArgumentOutOfRangeException(); 170 | 171 | return Native.hydro_pwhash_upgrade(key, masterKey, iterationsLimit, (IntPtr)memoryLimit, threads) == 0; 172 | } 173 | 174 | [MethodImpl(256)] 175 | public static void ExchangeKeygen(out KeyPair keyPair) { 176 | Native.hydro_kx_keygen(out keyPair); 177 | } 178 | 179 | [MethodImpl(256)] 180 | public static bool N1(out SessionKeyPair sessionKeyPair, byte[] packet, byte[] publicKey) { 181 | return Native.hydro_kx_n_1(out sessionKeyPair, packet, IntPtr.Zero, publicKey) == 0; 182 | } 183 | 184 | [MethodImpl(256)] 185 | public static bool N2(out SessionKeyPair sessionKeyPair, byte[] packet, ref KeyPair keyPair) { 186 | return Native.hydro_kx_n_2(out sessionKeyPair, packet, IntPtr.Zero, ref keyPair) == 0; 187 | } 188 | 189 | [MethodImpl(256)] 190 | public static bool KK1(out KeyState keyState, byte[] packet, byte[] publicKey, ref KeyPair keyPair) { 191 | return Native.hydro_kx_kk_1(out keyState, packet, publicKey, ref keyPair) == 0; 192 | } 193 | 194 | [MethodImpl(256)] 195 | public static bool KK2(out SessionKeyPair sessionKeyPair, byte[] packet, byte[] initialPacket, byte[] publicKey, ref KeyPair keyPair) { 196 | return Native.hydro_kx_kk_2(out sessionKeyPair, packet, initialPacket, publicKey, ref keyPair) == 0; 197 | } 198 | 199 | [MethodImpl(256)] 200 | public static bool KK3(ref KeyState keyState, out SessionKeyPair sessionKeyPair, byte[] packet, ref KeyPair keyPair) { 201 | return Native.hydro_kx_kk_3(ref keyState, out sessionKeyPair, packet, ref keyPair) == 0; 202 | } 203 | 204 | [MethodImpl(256)] 205 | public static void SecretKeygen(byte[] key) { 206 | if (key.Length != Library.secretKeyBytes) 207 | throw new ArgumentOutOfRangeException(); 208 | 209 | Native.hydro_secretbox_keygen(key); 210 | } 211 | 212 | [MethodImpl(256)] 213 | public static bool Encrypt(IntPtr packet, byte[] message, int messageLength, string context, byte[] key) { 214 | if (messageLength < 0) 215 | throw new ArgumentOutOfRangeException(); 216 | 217 | return Native.hydro_secretbox_encrypt(packet, message, messageLength, 0, context, key) == 0; 218 | } 219 | 220 | [MethodImpl(256)] 221 | public static bool Encrypt(byte[] packet, byte[] message, int messageLength, string context, byte[] key) { 222 | if (messageLength < 0) 223 | throw new ArgumentOutOfRangeException(); 224 | 225 | return Native.hydro_secretbox_encrypt(packet, message, messageLength, 0, context, key) == 0; 226 | } 227 | 228 | [MethodImpl(256)] 229 | public static bool Decrypt(byte[] message, IntPtr packet, int packetLength, string context, byte[] key) { 230 | if (packetLength < 0) 231 | throw new ArgumentOutOfRangeException(); 232 | 233 | return Native.hydro_secretbox_decrypt(message, packet, packetLength, 0, context, key) == 0; 234 | } 235 | 236 | [MethodImpl(256)] 237 | public static bool Decrypt(byte[] message, byte[] packet, int packetLength, string context, byte[] key) { 238 | if (packetLength < 0) 239 | throw new ArgumentOutOfRangeException(); 240 | 241 | return Native.hydro_secretbox_decrypt(message, packet, packetLength, 0, context, key) == 0; 242 | } 243 | 244 | [MethodImpl(256)] 245 | public static bool CreateProbe(byte[] probe, byte[] cipher, int cipherLength, string context, byte[] key) { 246 | if (probe.Length != Library.probeBytes || cipherLength < 0) 247 | throw new ArgumentOutOfRangeException(); 248 | 249 | return Native.hydro_secretbox_probe_create(probe, cipher, (IntPtr)cipherLength, context, key) == 0; 250 | } 251 | 252 | [MethodImpl(256)] 253 | public static bool VerifyProbe(byte[] probe, byte[] cipher, int cipherLength, string context, byte[] key) { 254 | if (probe.Length != Library.probeBytes || cipherLength < 0) 255 | throw new ArgumentOutOfRangeException(); 256 | 257 | return Native.hydro_secretbox_probe_verify(probe, cipher, (IntPtr)cipherLength, context, key) == 0; 258 | } 259 | 260 | [MethodImpl(256)] 261 | public static void SignKeygen(out SignKeyPair keyPair) { 262 | Native.hydro_sign_keygen(out keyPair); 263 | } 264 | 265 | [MethodImpl(256)] 266 | public static bool SignInit(out SignState signState, string context) { 267 | return Native.hydro_sign_init(out signState, context) == 0; 268 | } 269 | 270 | [MethodImpl(256)] 271 | public static bool SignCreate(byte[] sig, byte[] message, int messageLength, string context, byte[] key) { 272 | return Native.hydro_sign_create(sig, message, messageLength, context, key) == 0; 273 | } 274 | 275 | [MethodImpl(256)] 276 | public static bool SignVerify(byte[] sig, byte[] message, int messageLength, string context, byte[] key) { 277 | return Native.hydro_sign_verify(sig, message, messageLength, context, key) == 0; 278 | } 279 | } 280 | 281 | [SuppressUnmanagedCodeSecurity] 282 | internal static class Native { 283 | #if __IOS__ || UNITY_IOS && !UNITY_EDITOR 284 | private const string nativeLibrary = "__Internal"; 285 | #else 286 | private const string nativeLibrary = "hydrogen"; 287 | #endif 288 | 289 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 290 | internal static extern int hydro_init(); 291 | 292 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 293 | internal static extern uint hydro_random_u32(); 294 | 295 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 296 | internal static extern uint hydro_random_uniform(uint upperBound); 297 | 298 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 299 | internal static extern void hydro_hash_keygen(byte[] key); 300 | 301 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 302 | internal static extern int hydro_hash_hash(byte[] hash, IntPtr hashLength, byte[] message, IntPtr messageLength, string context, IntPtr key); 303 | 304 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 305 | internal static extern int hydro_hash_hash(byte[] hash, IntPtr hashLength, byte[] message, IntPtr messageLength, string context, byte[] key); 306 | 307 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 308 | internal static extern void hydro_pwhash_keygen(byte[] key); 309 | 310 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 311 | internal static extern int hydro_pwhash_deterministic(byte[] key, IntPtr keyLength, string password, IntPtr passwordLength, string context, byte[] masterKey, ulong iterationsLimit, IntPtr memoryLimit, byte threads); 312 | 313 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 314 | internal static extern int hydro_pwhash_create(byte[] key, string password, IntPtr passwordLength, byte[] masterKey, ulong iterationsLimit, IntPtr memoryLimit, byte threads); 315 | 316 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 317 | internal static extern int hydro_pwhash_verify(byte[] key, string password, IntPtr passwordLength, byte[] masterKey, ulong iterationsLimit, IntPtr memoryLimit, byte threads); 318 | 319 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 320 | internal static extern int hydro_pwhash_reencrypt(byte[] key, byte[] masterKey, byte[] newMasterKey); 321 | 322 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 323 | internal static extern int hydro_pwhash_upgrade(byte[] key, byte[] masterKey, ulong iterationsLimit, IntPtr memoryLimit, byte threads); 324 | 325 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 326 | internal static extern void hydro_kx_keygen(out KeyPair keyPair); 327 | 328 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 329 | internal static extern int hydro_kx_n_1(out SessionKeyPair sessionKeyPair, byte[] packet, IntPtr secretKey, byte[] publicKey); 330 | 331 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 332 | internal static extern int hydro_kx_n_2(out SessionKeyPair sessionKeyPair, byte[] packet, IntPtr secretKey, ref KeyPair keyPair); 333 | 334 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 335 | internal static extern int hydro_kx_kk_1(out KeyState keyState, byte[] packet, byte[] publicKey, ref KeyPair keyPair); 336 | 337 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 338 | internal static extern int hydro_kx_kk_2(out SessionKeyPair sessionKeyPair, byte[] packet, byte[] initialPacket, byte[] publicKey, ref KeyPair keyPair); 339 | 340 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 341 | internal static extern int hydro_kx_kk_3(ref KeyState keyState, out SessionKeyPair sessionKeyPair, byte[] packet, ref KeyPair keyPair); 342 | 343 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 344 | internal static extern void hydro_secretbox_keygen(byte[] key); 345 | 346 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 347 | internal static extern int hydro_secretbox_encrypt(IntPtr packet, byte[] message, int messageLength, ulong messageID, string context, byte[] key); 348 | 349 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 350 | internal static extern int hydro_secretbox_encrypt(byte[] packet, byte[] message, int messageLength, ulong messageID, string context, byte[] key); 351 | 352 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 353 | internal static extern int hydro_secretbox_decrypt(byte[] message, IntPtr packet, int packetLength, ulong messageID, string context, byte[] key); 354 | 355 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 356 | internal static extern int hydro_secretbox_decrypt(byte[] message, byte[] packet, int packetLength, ulong messageID, string context, byte[] key); 357 | 358 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 359 | internal static extern int hydro_secretbox_probe_create(byte[] probe, byte[] cipher, IntPtr cipherLength, string context, byte[] key); 360 | 361 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 362 | internal static extern int hydro_secretbox_probe_verify(byte[] probe, byte[] cipher, IntPtr cipherLength, string context, byte[] key); 363 | 364 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 365 | internal static extern void hydro_sign_keygen(out SignKeyPair keyPair); 366 | 367 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 368 | internal static extern int hydro_sign_init(out SignState signState, string context); 369 | 370 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 371 | internal static extern int hydro_sign_create(byte[] csig, byte[] message, int messageLength, string context, byte[] key); 372 | 373 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)] 374 | internal static extern int hydro_sign_verify(byte[] csig, byte[] message, int messageLength, string context, byte[] key); 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Stanislav Denisov (nxrighthere@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |