< Summary

Information
Class: Renci.SshNet.Security.Cryptography.BCrypt
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Bcrypt.cs
Line coverage
72%
Covered lines: 454
Uncovered lines: 168
Coverable lines: 622
Total lines: 952
Line coverage: 72.9%
Branch coverage
33%
Covered branches: 38
Total branches: 112
Branch coverage: 33.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.cctor()100%1100%
HashString(...)100%10%
HashString(...)100%10%
HashPassword(...)100%10%
HashPassword(...)100%10%
HashPassword(...)0%200%
GenerateSalt(...)0%40%
GenerateSalt()100%10%
Verify(...)100%10%
EncodeBase64(...)0%100%
DecodeBase64(...)0%220%
Char64(...)0%40%
Encipher(...)100%2100%
StreamToWord(...)100%2100%
InitializeKey()100%1100%
Key(...)100%6100%
EKSKey(...)100%6100%
CryptRaw(...)0%140%
Hash(...)100%8100%
Pbkdf(...)100%10100%
AppendArrays(...)100%4100%
.ctor()100%10%
.ctor(...)100%10%
.ctor(...)100%10%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Security\Cryptography\Bcrypt.cs

#LineLine coverage
 1//
 2// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
 3// Copyright (c) 2010 Ryan D. Emerle
 4//
 5// Permission to use, copy, modify, and distribute this software for any
 6// purpose with or without fee is hereby granted, provided that the above
 7// copyright notice and this permission notice appear in all copies.
 8//
 9// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 10// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 11// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 12// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 13// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 14// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 15// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 16
 17using Renci.SshNet.Abstractions;
 18using System;
 19using System.Diagnostics;
 20using System.Security.Cryptography;
 21using System.Text;
 22
 23namespace Renci.SshNet.Security.Cryptography
 24{
 25    /// <summary>BCrypt implementation.</summary>
 26    /// <remarks>
 27    ///  <para>
 28    ///        BCrypt implements OpenBSD-style Blowfish password hashing using the scheme described in
 29    ///        <a href="http://www.usenix.org/event/usenix99/provos/provos_html/index.html">"A Future-
 30    ///        Adaptable Password Scheme"</a> by Niels Provos and David Mazieres.
 31    ///  </para>
 32    ///  <para>
 33    ///        This password hashing system tries to thwart off-line password cracking using a
 34    ///        computationally-intensive hashing algorithm, based on Bruce Schneier's Blowfish cipher.
 35    ///        The work factor of the algorithm is parameterised, so it can be increased as computers
 36    ///        get faster.
 37    ///  </para>
 38    ///  <para>
 39    ///        Usage is really simple. To hash a password for the first time, call the <see
 40    ///        cref="HashPassword(string)"/> method with a random salt, like this:
 41    ///  </para>
 42    ///  <code>string pw_hash = BCrypt.HashPassword(plain_password);</code>
 43    ///  <para>
 44    ///        To check whether a plaintext password matches one that has been hashed previously,
 45    ///        use the <see cref="Verify"/> method:
 46    ///  </para>
 47    ///  <code>
 48    ///     if (BCrypt.Verify(candidate_password, stored_hash))
 49    ///         Console.WriteLine("It matches");
 50    ///     else
 51    ///         Console.WriteLine("It does not match");
 52    ///   </code>
 53    ///   <para>
 54    ///         The <see cref="GenerateSalt()"/> method takes an optional parameter (workFactor) that
 55    ///         determines the computational complexity of the hashing:
 56    ///   </para>
 57    ///   <code>
 58    ///     string strong_salt = BCrypt.GenerateSalt(10);
 59    ///     string stronger_salt = BCrypt.GenerateSalt(12);
 60    ///   </code>
 61    ///   <para>
 62    ///         The amount of work increases exponentially (2^workFactor), so each increment is twice
 63    ///         as much work. The default workFactor is 10, and the valid range is 4 to 31.
 64    ///   </para>
 65    /// </remarks>
 66    internal sealed class BCrypt
 67    {
 68        // BCrypt parameters
 69        private const int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
 70        private const int BCRYPT_SALT_LEN = 16;
 71
 72        // Blowfish parameters
 73        private const int BLOWFISH_NUM_ROUNDS = 16;
 74
 75        // Initial contents of key schedule
 476        private static readonly uint[] _POrig = {
 477            0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
 478            0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
 479            0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
 480            0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
 481            0x9216d5d9, 0x8979fb1b
 482        };
 83
 484        private static readonly uint[] _SOrig = {
 485            0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
 486            0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
 487            0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
 488            0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
 489            0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
 490            0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
 491            0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
 492            0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
 493            0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
 494            0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
 495            0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
 496            0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
 497            0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
 498            0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
 499            0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
 4100            0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
 4101            0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
 4102            0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
 4103            0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
 4104            0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
 4105            0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
 4106            0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
 4107            0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
 4108            0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
 4109            0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
 4110            0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
 4111            0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
 4112            0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
 4113            0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
 4114            0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
 4115            0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
 4116            0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
 4117            0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
 4118            0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
 4119            0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
 4120            0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
 4121            0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
 4122            0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
 4123            0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
 4124            0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
 4125            0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
 4126            0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
 4127            0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
 4128            0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
 4129            0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
 4130            0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
 4131            0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
 4132            0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
 4133            0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
 4134            0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
 4135            0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
 4136            0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
 4137            0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
 4138            0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
 4139            0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
 4140            0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
 4141            0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
 4142            0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
 4143            0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
 4144            0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
 4145            0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
 4146            0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
 4147            0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
 4148            0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
 4149            0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
 4150            0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
 4151            0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
 4152            0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
 4153            0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
 4154            0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
 4155            0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
 4156            0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
 4157            0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
 4158            0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
 4159            0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
 4160            0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
 4161            0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
 4162            0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
 4163            0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
 4164            0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
 4165            0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
 4166            0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
 4167            0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
 4168            0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
 4169            0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
 4170            0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
 4171            0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
 4172            0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
 4173            0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
 4174            0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
 4175            0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
 4176            0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
 4177            0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
 4178            0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
 4179            0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
 4180            0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
 4181            0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
 4182            0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
 4183            0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
 4184            0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
 4185            0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
 4186            0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
 4187            0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
 4188            0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
 4189            0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
 4190            0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
 4191            0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
 4192            0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
 4193            0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
 4194            0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
 4195            0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
 4196            0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
 4197            0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
 4198            0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
 4199            0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
 4200            0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
 4201            0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
 4202            0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
 4203            0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
 4204            0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
 4205            0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
 4206            0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
 4207            0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
 4208            0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
 4209            0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
 4210            0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
 4211            0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
 4212            0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
 4213            0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
 4214            0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
 4215            0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
 4216            0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
 4217            0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
 4218            0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
 4219            0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
 4220            0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
 4221            0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
 4222            0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
 4223            0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
 4224            0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
 4225            0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
 4226            0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
 4227            0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
 4228            0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
 4229            0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
 4230            0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
 4231            0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
 4232            0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
 4233            0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
 4234            0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
 4235            0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
 4236            0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
 4237            0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
 4238            0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
 4239            0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
 4240            0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
 4241            0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
 4242            0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
 4243            0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
 4244            0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
 4245            0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
 4246            0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
 4247            0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
 4248            0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
 4249            0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
 4250            0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
 4251            0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
 4252            0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
 4253            0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
 4254            0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
 4255            0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
 4256            0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
 4257            0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
 4258            0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
 4259            0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
 4260            0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
 4261            0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
 4262            0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
 4263            0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
 4264            0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
 4265            0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
 4266            0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
 4267            0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
 4268            0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
 4269            0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
 4270            0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
 4271            0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
 4272            0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
 4273            0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
 4274            0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
 4275            0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
 4276            0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
 4277            0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
 4278            0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
 4279            0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
 4280            0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
 4281            0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
 4282            0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
 4283            0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
 4284            0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
 4285            0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
 4286            0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
 4287            0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
 4288            0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
 4289            0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
 4290            0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
 4291            0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
 4292            0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
 4293            0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
 4294            0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
 4295            0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
 4296            0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
 4297            0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
 4298            0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
 4299            0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
 4300            0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
 4301            0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
 4302            0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
 4303            0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
 4304            0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
 4305            0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
 4306            0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
 4307            0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
 4308            0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
 4309            0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
 4310            0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
 4311            0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
 4312            0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
 4313            0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
 4314            0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
 4315            0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
 4316            0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
 4317            0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
 4318            0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
 4319            0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
 4320            0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
 4321            0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
 4322            0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
 4323            0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
 4324            0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
 4325            0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
 4326            0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
 4327            0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
 4328            0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
 4329            0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
 4330            0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
 4331            0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
 4332            0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
 4333            0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
 4334            0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
 4335            0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
 4336            0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
 4337            0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
 4338            0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
 4339            0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
 4340            0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
 4341        };
 342
 343        // OpenBSD IV: "OxychromaticBlowfishSwatDynamite" in big endian
 4344        private static readonly uint[] _OpenBsdIv = new uint[] {
 4345            0x4f787963, 0x68726f6d, 0x61746963, 0x426c6f77,
 4346            0x66697368, 0x53776174, 0x44796e61, 0x6d697465,
 4347        };
 348
 349        // bcrypt IV: "OrpheanBeholderScryDoubt"
 4350        private static readonly uint[] _BfCryptCiphertext = {
 4351            0x4f727068, 0x65616e42, 0x65686f6c,
 4352            0x64657253, 0x63727944, 0x6f756274
 4353        };
 354
 355        // Table for Base64 encoding
 4356        private static readonly char[] _Base64Code = {
 4357            '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
 4358            'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
 4359            'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
 4360            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
 4361            'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
 4362            '6', '7', '8', '9'
 4363        };
 364
 365        // Table for Base64 decoding
 4366        private static readonly int[] _Index64 = {
 4367            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 4368            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 4369            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 4370            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 4371            -1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
 4372            56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
 4373            -1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
 4374            7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
 4375            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
 4376            -1, -1, -1, -1, -1, -1, 28, 29, 30,
 4377            31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 4378            41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
 4379            51, 52, 53, -1, -1, -1, -1, -1
 4380        };
 381
 382        // Expanded Blowfish key
 383        private uint[] _P;
 384        private uint[] _S;
 385
 386        /// <summary>
 387        ///  Hash a string using the OpenBSD bcrypt scheme and a salt generated by <see
 388        ///  cref="BCrypt.GenerateSalt()"/>.
 389        /// </summary>
 390        /// <remarks>Just an alias for HashPassword.</remarks>
 391        /// <param name="source">The string to hash.</param>
 392        /// <returns>The hashed string.</returns>
 393        public static string HashString(string source)
 0394        {
 0395            return HashPassword(source);
 0396        }
 397
 398        /// <summary>
 399        ///  Hash a string using the OpenBSD bcrypt scheme and a salt generated by <see
 400        ///  cref="BCrypt.GenerateSalt()"/>.
 401        /// </summary>
 402        /// <remarks>Just an alias for HashPassword.</remarks>
 403        /// <param name="source">  The string to hash.</param>
 404        /// <param name="workFactor">The log2 of the number of rounds of hashing to apply - the work
 405        ///                          factor therefore increases as 2^workFactor.</param>
 406        /// <returns>The hashed string.</returns>
 407        public static string HashString(string source, int workFactor)
 0408        {
 0409            return HashPassword(source, GenerateSalt(workFactor));
 0410        }
 411
 412        /// <summary>
 413        ///  Hash a password using the OpenBSD bcrypt scheme and a salt generated by <see
 414        ///  cref="BCrypt.GenerateSalt()"/>.
 415        /// </summary>
 416        /// <param name="input">The password to hash.</param>
 417        /// <returns>The hashed password.</returns>
 418        public static string HashPassword(string input)
 0419        {
 0420            return HashPassword(input, GenerateSalt());
 0421        }
 422
 423        /// <summary>
 424        ///  Hash a password using the OpenBSD bcrypt scheme and a salt generated by <see
 425        ///  cref="BCrypt.GenerateSalt(int)"/> using the given <paramref name="workFactor"/>.
 426        /// </summary>
 427        /// <param name="input">     The password to hash.</param>
 428        /// <param name="workFactor">The log2 of the number of rounds of hashing to apply - the work
 429        ///                          factor therefore increases as 2^workFactor.</param>
 430        /// <returns>The hashed password.</returns>
 431        public static string HashPassword(string input, int workFactor)
 0432        {
 0433            return HashPassword(input, GenerateSalt(workFactor));
 0434        }
 435
 436        /// <summary>Hash a password using the OpenBSD bcrypt scheme.</summary>
 437        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 438        ///                                     illegal values.</exception>
 439        /// <param name="input">The password to hash.</param>
 440        /// <param name="salt">    the salt to hash with (perhaps generated using BCrypt.gensalt).</param>
 441        /// <returns>The hashed password</returns>
 442        public static string HashPassword(string input, string salt)
 0443        {
 0444            if (input == null)
 0445                throw new ArgumentNullException("input");
 446
 0447            if (string.IsNullOrEmpty(salt))
 0448                throw new ArgumentException("Invalid salt", "salt");
 449
 450            // Determinthe starting offset and validate the salt
 451            int startingOffset;
 0452            char minor = (char)0;
 0453            if (salt[0] != '$' || salt[1] != '2')
 0454                throw new SaltParseException("Invalid salt version");
 0455            if (salt[2] == '$')
 0456                startingOffset = 3;
 457            else
 0458            {
 0459                minor = salt[2];
 0460                if (minor != 'a' || salt[3] != '$')
 0461                    throw new SaltParseException("Invalid salt revision");
 0462                startingOffset = 4;
 0463            }
 464
 465            // Extract number of rounds
 0466            if (salt[startingOffset + 2] > '$')
 0467                throw new SaltParseException("Missing salt rounds");
 468
 469            // Extract details from salt
 0470            int logRounds = Convert.ToInt32(salt.Substring(startingOffset, 2));
 0471            string extractedSalt = salt.Substring(startingOffset + 3, 22);
 472
 0473            byte[] inputBytes = Encoding.UTF8.GetBytes((input + (minor >= 'a' ? "\0" : "")));
 0474            byte[] saltBytes = DecodeBase64(extractedSalt, BCRYPT_SALT_LEN);
 475
 0476            BCrypt bCrypt = new BCrypt();
 0477            byte[] hashed = bCrypt.CryptRaw(inputBytes, saltBytes, logRounds);
 478
 479            // Generate result string
 0480            StringBuilder result = new StringBuilder();
 0481            result.Append("$2");
 0482            if (minor >= 'a')
 0483                result.Append(minor);
 0484            result.AppendFormat("${0:00}$", logRounds);
 0485            result.Append(EncodeBase64(saltBytes, saltBytes.Length));
 0486            result.Append(EncodeBase64(hashed, (_BfCryptCiphertext.Length * 4) - 1));
 0487            return result.ToString();
 0488        }
 489
 490        /// <summary>
 491        ///  Generate a salt for use with the <see cref="BCrypt.HashPassword(string,string)"/> method.
 492        /// </summary>
 493        /// <param name="workFactor">The log2 of the number of rounds of hashing to apply - the work
 494        ///                          factor therefore increases as 2**workFactor.</param>
 495        /// <returns>A base64 encoded salt value.</returns>
 496        public static string GenerateSalt(int workFactor)
 0497        {
 0498            if (workFactor < 4 || workFactor > 31)
 0499                throw new ArgumentOutOfRangeException("workFactor", "The work factor must be between 4 and 31 (inclusive
 500
 0501            byte[] rnd = new byte[BCRYPT_SALT_LEN];
 502
 0503            RandomNumberGenerator rng = RandomNumberGenerator.Create();
 504
 0505            rng.GetBytes(rnd);
 506
 0507            StringBuilder rs = new StringBuilder();
 0508            rs.AppendFormat("$2a${0:00}$", workFactor);
 0509            rs.Append(EncodeBase64(rnd, rnd.Length));
 0510            return rs.ToString();
 0511        }
 512
 513        /// <summary>
 514        ///  Generate a salt for use with the <see cref="BCrypt.HashPassword(string,string)"/> method
 515        ///  selecting a reasonable default for the number of hashing rounds to apply.
 516        /// </summary>
 517        /// <returns>A base64 encoded salt value.</returns>
 518        public static string GenerateSalt()
 0519        {
 0520            return GenerateSalt(GENSALT_DEFAULT_LOG2_ROUNDS);
 0521        }
 522
 523        /// <summary>
 524        ///  Verifies that the hash of the given <paramref name="text"/> matches the provided
 525        ///  <paramref name="hash"/>
 526        /// </summary>
 527        /// <param name="text">The text to verify.</param>
 528        /// <param name="hash"> The previously-hashed password.</param>
 529        /// <returns>true if the passwords match, false otherwise.</returns>
 530        public static bool Verify(string text, string hash)
 0531        {
 0532            return hash == HashPassword(text, hash);
 0533        }
 534
 535        /// <summary>
 536        ///  Encode a byte array using bcrypt's slightly-modified base64 encoding scheme. Note that this
 537        ///  is *not* compatible with the standard MIME-base64 encoding.
 538        /// </summary>
 539        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 540        ///                                     illegal values.</exception>
 541        /// <param name="byteArray">The byte array to encode.</param>
 542        /// <param name="length">   The number of bytes to encode.</param>
 543        /// <returns>Base64-encoded string.</returns>
 544        private static string EncodeBase64(byte[] byteArray, int length)
 0545        {
 0546            if (length <= 0 || length > byteArray.Length)
 0547                throw new ArgumentException("Invalid length", "length");
 548
 0549            int off = 0;
 0550            StringBuilder rs = new StringBuilder();
 0551            while (off < length)
 0552            {
 0553                int c1 = byteArray[off++] & 0xff;
 0554                rs.Append(_Base64Code[(c1 >> 2) & 0x3f]);
 0555                c1 = (c1 & 0x03) << 4;
 0556                if (off >= length)
 0557                {
 0558                    rs.Append(_Base64Code[c1 & 0x3f]);
 0559                    break;
 560                }
 0561                int c2 = byteArray[off++] & 0xff;
 0562                c1 |= (c2 >> 4) & 0x0f;
 0563                rs.Append(_Base64Code[c1 & 0x3f]);
 0564                c1 = (c2 & 0x0f) << 2;
 0565                if (off >= length)
 0566                {
 0567                    rs.Append(_Base64Code[c1 & 0x3f]);
 0568                    break;
 569                }
 0570                c2 = byteArray[off++] & 0xff;
 0571                c1 |= (c2 >> 6) & 0x03;
 0572                rs.Append(_Base64Code[c1 & 0x3f]);
 0573                rs.Append(_Base64Code[c2 & 0x3f]);
 0574            }
 0575            return rs.ToString();
 0576        }
 577
 578        /// <summary>
 579        ///  Decode a string encoded using bcrypt's base64 scheme to a byte array. Note that this is *not*
 580        ///  compatible with the standard MIME-base64 encoding.
 581        /// </summary>
 582        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 583        ///                                     illegal values.</exception>
 584        /// <param name="encodedstring">The string to decode.</param>
 585        /// <param name="maximumBytes"> The maximum bytes to decode.</param>
 586        /// <returns>The decoded byte array.</returns>
 587        private static byte[] DecodeBase64(string encodedstring, int maximumBytes)
 0588        {
 0589            int position = 0,
 0590                sourceLength = encodedstring.Length,
 0591                outputLength = 0;
 592
 0593            if (maximumBytes <= 0)
 0594                throw new ArgumentException("Invalid maximum bytes value", "maximumBytes");
 595
 596            // TODO: update to use a List<byte> - it's only ever 16 bytes, so it's not a big deal
 0597            StringBuilder rs = new StringBuilder();
 0598            while (position < sourceLength - 1 && outputLength < maximumBytes)
 0599            {
 0600                int c1 = Char64(encodedstring[position++]);
 0601                int c2 = Char64(encodedstring[position++]);
 0602                if (c1 == -1 || c2 == -1)
 0603                    break;
 604
 0605                rs.Append((char)((c1 << 2) | ((c2 & 0x30) >> 4)));
 0606                if (++outputLength >= maximumBytes || position >= sourceLength)
 0607                    break;
 608
 0609                int c3 = Char64(encodedstring[position++]);
 0610                if (c3 == -1)
 0611                    break;
 612
 0613                rs.Append((char)(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)));
 0614                if (++outputLength >= maximumBytes || position >= sourceLength)
 0615                    break;
 616
 0617                int c4 = Char64(encodedstring[position++]);
 0618                rs.Append((char)(((c3 & 0x03) << 6) | c4));
 619
 0620                ++outputLength;
 0621            }
 622
 0623            byte[] ret = new byte[outputLength];
 0624            for (position = 0; position < outputLength; position++)
 0625                ret[position] = (byte)rs[position];
 0626            return ret;
 0627        }
 628
 629        /// <summary>
 630        ///  Look up the 3 bits base64-encoded by the specified character, range-checking against
 631        ///  conversion table.
 632        /// </summary>
 633        /// <param name="character">The base64-encoded value.</param>
 634        /// <returns>The decoded value of x.</returns>
 635        private static int Char64(char character)
 0636        {
 0637            if (character < 0 || character > _Index64.Length)
 0638                return -1;
 0639            return _Index64[character];
 0640        }
 641
 642        /// <summary>Blowfish encipher a single 64-bit block encoded as two 32-bit halves.</summary>
 643        /// <param name="blockArray">An array containing the two 32-bit half blocks.</param>
 644        /// <param name="offset">    The position in the array of the blocks.</param>
 645        private void Encipher(uint[] blockArray, int offset)
 38859840646        {
 647            uint round,
 648                     n,
 38859840649                     block = blockArray[offset],
 38859840650                     r = blockArray[offset + 1];
 651
 38859840652            block ^= _P[0];
 388598400653            for (round = 0; round <= BLOWFISH_NUM_ROUNDS - 2;)
 310878720654            {
 655                // Feistel substitution on left word
 310878720656                n = _S[(block >> 24) & 0xff];
 310878720657                n += _S[0x100 | ((block >> 16) & 0xff)];
 310878720658                n ^= _S[0x200 | ((block >> 8) & 0xff)];
 310878720659                n += _S[0x300 | (block & 0xff)];
 310878720660                r ^= n ^ _P[++round];
 661
 662                // Feistel substitution on right word
 310878720663                n = _S[(r >> 24) & 0xff];
 310878720664                n += _S[0x100 | ((r >> 16) & 0xff)];
 310878720665                n ^= _S[0x200 | ((r >> 8) & 0xff)];
 310878720666                n += _S[0x300 | (r & 0xff)];
 310878720667                block ^= n ^ _P[++round];
 310878720668            }
 38859840669            blockArray[offset] = r ^ _P[BLOWFISH_NUM_ROUNDS + 1];
 38859840670            blockArray[offset + 1] = block;
 38859840671        }
 672
 673        /// <summary>Cycically extract a word of key material.</summary>
 674        /// <param name="data">The string to extract the data from.</param>
 675        /// <param name="offset"> [in,out] The current offset.</param>
 676        /// <returns>The next word of material from data.</returns>
 677        private static uint StreamToWord(byte[] data, ref int offset)
 1937664678        {
 679            int i;
 1937664680            uint word = 0;
 681
 19376640682            for (i = 0; i < 4; i++)
 7750656683            {
 7750656684                word = (word << 8) | (uint)(data[offset] & 0xff);
 7750656685                offset = (offset + 1) % data.Length;
 7750656686            }
 1937664687            return word;
 1937664688        }
 689
 690        /// <summary>Initializes the Blowfish key schedule.</summary>
 691        private void InitializeKey()
 576692        {
 576693            _P = new uint[_POrig.Length];
 576694            _S = new uint[_SOrig.Length];
 576695            Array.Copy(_POrig, _P, _POrig.Length);
 576696            Array.Copy(_SOrig, _S, _SOrig.Length);
 576697        }
 698
 699        /// <summary>Key the Blowfish cipher.</summary>
 700        /// <param name="keyBytes">The key byte array.</param>
 701        private void Key(byte[] keyBytes)
 73728702        {
 703            int i;
 73728704            int koffp = 0;
 73728705            uint[] lr = { 0, 0 };
 147456706            int plen = _P.Length, slen = _S.Length;
 707
 2801664708            for (i = 0; i < plen; i++)
 1327104709                _P[i] = _P[i] ^ StreamToWord(keyBytes, ref koffp);
 710
 1474560711            for (i = 0; i < plen; i += 2)
 663552712            {
 663552713                Encipher(lr, 0);
 663552714                _P[i] = lr[0];
 663552715                _P[i + 1] = lr[1];
 663552716            }
 717
 75644928718            for (i = 0; i < slen; i += 2)
 37748736719            {
 37748736720                Encipher(lr, 0);
 37748736721                _S[i] = lr[0];
 37748736722                _S[i + 1] = lr[1];
 37748736723            }
 73728724        }
 725
 726        /// <summary>
 727        ///  Perform the "enhanced key schedule" step described by Provos and Mazieres in "A Future-
 728        ///  Adaptable Password Scheme" http://www.openbsd.org/papers/bcrypt-paper.ps.
 729        /// </summary>
 730        /// <param name="saltBytes"> Salt byte array.</param>
 731        /// <param name="inputBytes">Input byte array.</param>
 732        private void EKSKey(byte[] saltBytes, byte[] inputBytes)
 576733        {
 734            int i;
 576735            int passwordOffset = 0,
 576736                saltOffset = 0;
 576737            uint[] lr = { 0, 0 };
 1152738            int plen = _P.Length, slen = _S.Length;
 739
 21888740            for (i = 0; i < plen; i++)
 10368741                _P[i] = _P[i] ^ StreamToWord(inputBytes, ref passwordOffset);
 742
 11520743            for (i = 0; i < plen; i += 2)
 5184744            {
 5184745                lr[0] ^= StreamToWord(saltBytes, ref saltOffset);
 5184746                lr[1] ^= StreamToWord(saltBytes, ref saltOffset);
 5184747                Encipher(lr, 0);
 5184748                _P[i] = lr[0];
 5184749                _P[i + 1] = lr[1];
 5184750            }
 751
 590976752            for (i = 0; i < slen; i += 2)
 294912753            {
 294912754                lr[0] ^= StreamToWord(saltBytes, ref saltOffset);
 294912755                lr[1] ^= StreamToWord(saltBytes, ref saltOffset);
 294912756                Encipher(lr, 0);
 294912757                _S[i] = lr[0];
 294912758                _S[i + 1] = lr[1];
 294912759            }
 576760        }
 761
 762        /// <summary>Perform the central hashing step in the bcrypt scheme.</summary>
 763        /// <exception cref="ArgumentException">Thrown when one or more arguments have unsupported or
 764        ///                                     illegal values.</exception>
 765        /// <param name="inputBytes">The input byte array to hash.</param>
 766        /// <param name="saltBytes"> The salt byte array to hash with.</param>
 767        /// <param name="logRounds"> The binary logarithm of the number of rounds of hashing to apply.</param>
 768        /// <returns>A byte array containing the hashed result.</returns>
 769        private byte[] CryptRaw(byte[] inputBytes, byte[] saltBytes, int logRounds)
 0770        {
 0771            uint[] cdata = new uint[_BfCryptCiphertext.Length];
 0772            Array.Copy(_BfCryptCiphertext, cdata, _BfCryptCiphertext.Length);
 0773            int clen = cdata.Length;
 774
 0775            if (logRounds < 4 || logRounds > 31)
 0776                throw new ArgumentException("Bad number of rounds", "logRounds");
 777
 0778            if (saltBytes.Length != BCRYPT_SALT_LEN)
 0779                throw new ArgumentException("Bad salt Length", "saltBytes");
 780
 0781            uint rounds = 1u << logRounds;
 0782            Debug.Assert(rounds > 0, "Rounds must be > 0"); // We overflowed rounds at 31 - added safety check
 783
 0784            InitializeKey();
 0785            EKSKey(saltBytes, inputBytes);
 786
 0787            for (int i = 0; i < rounds; i++)
 0788            {
 0789                Key(inputBytes);
 0790                Key(saltBytes);
 0791            }
 792
 0793            for (int i = 0; i < 64; i++)
 0794            {
 0795                for (int j = 0; j < (clen >> 1); j++)
 0796                    Encipher(cdata, j << 1);
 0797            }
 798
 0799            byte[] ret = new byte[clen * 4];
 0800            for (int i = 0, j = 0; i < clen; i++)
 0801            {
 0802                ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
 0803                ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
 0804                ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
 0805                ret[j++] = (byte)(cdata[i] & 0xff);
 0806            }
 0807            return ret;
 0808        }
 809
 810        /**
 811         * Compatibility with new OpenBSD function.
 812         * Ported from SSHJ library (https://github.com/hierynomus/sshj)
 813         */
 814        public void Hash(byte[] hpass, byte[] hsalt, byte[] output)
 576815        {
 576816            InitializeKey();
 576817            EKSKey(hsalt, hpass);
 74880818            for (int i = 0; i < 64; i++)
 36864819            {
 36864820                Key(hsalt);
 36864821                Key(hpass);
 36864822            }
 823
 576824            uint[] buf = new uint[_OpenBsdIv.Length];
 576825            Array.Copy(_OpenBsdIv, 0, buf, 0, _OpenBsdIv.Length);
 5760826            for (int i = 0; i < 8; i += 2)
 2304827            {
 299520828                for (int j = 0; j < 64; j++)
 147456829                {
 147456830                    Encipher(buf, i);
 147456831                }
 2304832            }
 833
 10944834            for (int i = 0, j = 0; i < buf.Length; i++)
 4608835            {
 836                // Output of this is little endian
 4608837                output[j++] = (byte)(buf[i] & 0xff);
 4608838                output[j++] = (byte)((buf[i] >> 8) & 0xff);
 4608839                output[j++] = (byte)((buf[i] >> 16) & 0xff);
 4608840                output[j++] = (byte)((buf[i] >> 24) & 0xff);
 4608841            }
 576842        }
 843
 844        /// <summary>
 845        /// Applies the Bcrypt kdf to derive a key and iv from the passphrase,
 846        /// the key/iv are returned in the output variable.
 847        /// Ported from the SSHJ library. https://github.com/hierynomus/sshj
 848        /// </summary>
 849        /// <param name="password"></param>
 850        /// <param name="salt"></param>
 851        /// <param name="rounds"></param>
 852        /// <param name="output"></param>
 853        public void Pbkdf(byte[] password, byte[] salt, int rounds, byte[] output)
 18854        {
 18855            using (var sha512 = CryptoAbstraction.CreateSHA512())
 18856            {
 18857                int nblocks = (output.Length + 31) / 32;
 18858                byte[] hpass = sha512.ComputeHash(password);
 859
 18860                byte[] hsalt = new byte[64];
 18861                byte[] block_b = new byte[4];
 18862                byte[] outBytes = new byte[32];
 18863                byte[] tmp = new byte[32];
 108864                for (int block = 1; block <= nblocks; block++)
 36865                {
 866                    // Block count is in big endian
 36867                    block_b[0] = (byte)((block >> 24) & 0xFF);
 36868                    block_b[1] = (byte)((block >> 16) & 0xFF);
 36869                    block_b[2] = (byte)((block >> 8) & 0xFF);
 36870                    block_b[3] = (byte)(block & 0xFF);
 871
 36872                    hsalt = sha512.ComputeHash(AppendArrays(salt, block_b));
 36873                    Hash(hpass, hsalt, outBytes);
 36874                    Array.Copy(outBytes, 0, tmp, 0, outBytes.Length);
 875
 1152876                    for (int round = 1; round < rounds; round++)
 540877                    {
 540878                        hsalt = sha512.ComputeHash(tmp);
 540879                        Hash(hpass, hsalt, tmp);
 880
 35640881                        for (int i = 0; i < tmp.Length; i++)
 17280882                        {
 17280883                            outBytes[i] ^= tmp[i];
 17280884                        }
 540885                    }
 886
 2376887                    for (int i = 0; i < outBytes.Length; i++)
 1152888                    {
 1152889                        int idx = i * nblocks + (block - 1);
 1152890                        if (idx < output.Length)
 864891                        {
 864892                            output[idx] = outBytes[i];
 864893                        }
 1152894                    }
 36895                }
 18896            }
 18897        }
 898
 899        /// <summary>
 900        /// Appends multiple byte arrays into one array.
 901        /// </summary>
 902        /// <param name="b1"></param>
 903        /// <param name="others"></param>
 904        /// <returns></returns>
 905        private byte[] AppendArrays(byte[] b1, params byte[][] others)
 36906        {
 907            //from https://stackoverflow.com/questions/46534429/how-to-convert-java-messagedigest-with-two-update-statem
 36908            int n = b1.Length;
 180909            foreach (var other in others)
 36910            {
 36911                n += other.Length;
 36912            }
 913
 36914            var result = new byte[n];
 915
 36916            n = 0;
 36917            Array.Copy(b1, 0, result, n, b1.Length);
 36918            n += b1.Length;
 180919            foreach (var other in others)
 36920            {
 36921                Array.Copy(other, 0, result, n, other.Length);
 36922                n += other.Length;
 36923            }
 924
 36925            return result;
 36926        }
 927
 928        /// <summary>Exception for signalling parse errors. </summary>
 929        public class SaltParseException : Exception
 930        {
 931            /// <summary>Default constructor. </summary>
 0932            public SaltParseException()
 0933            {
 0934            }
 935
 936            /// <summary>Initializes a new instance of <see cref="SaltParseException"/>.</summary>
 937            /// <param name="message">The message.</param>
 938            public SaltParseException(string message)
 0939                : base(message)
 0940            {
 0941            }
 942
 943            /// <summary>Initializes a new instance of <see cref="SaltParseException"/>.</summary>
 944            /// <param name="message">       The message.</param>
 945            /// <param name="innerException">The inner exception.</param>
 946            public SaltParseException(string message, Exception innerException)
 0947                : base(message, innerException)
 0948            {
 0949            }
 950        }
 951    }
 952}