1- public struct Hasher {
1+ extension Bcrypt {
22 @usableFromInline static let cipherText = Array ( " OrpheanBeholderScryDoubt " . utf8)
33 @usableFromInline static let maxSalt = 16
44 @usableFromInline static let saltSpace = 22
55 @usableFromInline static let words = 6
66 @usableFromInline static let hashSpace = 60
77
8- @usableFromInline let version : BcryptVersion
9-
10- public init ( version: BcryptVersion = . v2a) {
11- self . version = version
8+ /// Hashes a password using the bcrypt algorithm.
9+ /// - Parameters:
10+ /// - password: the password to hash.
11+ /// - cost: number of rounds to apply the key derivation function, used as log2(cost). Must be between 4 and 31.
12+ /// - version: the version of the bcrypt algorithm to use. Defaults to `v2b`.
13+ /// - Throws: ``BcryptError``
14+ /// - Returns: the hashed password.
15+ @inlinable
16+ public static func hash( password: String , cost: Int = 10 , version: BcryptVersion = . v2b) throws -> String {
17+ String (
18+ decoding: try hash ( password: Array ( password. utf8) , cost: cost, salt: Self . generateRandomSalt ( ) , version: version) ,
19+ as: UTF8 . self
20+ )
1221 }
1322
14- /// Encrypts a password using the bcrypt algorithm.
23+ /// Hashes a password using the bcrypt algorithm.
1524 /// - Parameters:
16- /// - cost: number of rounds to apply the key derivation function, used as log2(cost)
17- /// - password: the password to hash
18- /// - Throws:
19- /// - Returns:
25+ /// - password: the password to hash.
26+ /// - cost: number of rounds to apply the key derivation function, used as log2(cost). Must be between 4 and 31.
27+ /// - version: the version of the bcrypt algorithm to use. Defaults to `v2b`.
28+ /// - Throws: ``BcryptError``
29+ /// - Returns: the hashed password.
2030 @inlinable
21- public func hash( password: [ UInt8 ] , cost: Int ) throws -> [ UInt8 ] {
22- try hash ( password: password, cost: cost, salt: Hasher . generateRandomSalt ( ) )
31+ public static func hash( password: [ UInt8 ] , cost: Int = 10 , version : BcryptVersion = . v2b ) throws -> [ UInt8 ] {
32+ try hash ( password: password, cost: cost, salt: Self . generateRandomSalt ( ) , version : version )
2333 }
2434
35+ /// Hashes a password using the bcrypt algorithm.
36+ /// - Parameters:
37+ /// - password: the password to hash.
38+ /// - cost: number of rounds to apply the key derivation function, used as log2(cost). Must be between 4 and 31.
39+ /// - salt: the salt to use for the hash.
40+ /// - version: the version of the bcrypt algorithm to use. Defaults to `v2b`.
41+ /// - Throws: ``BcryptError``
42+ /// - Returns: the hashed password.
2543 @inlinable
26- public func hash( password: [ UInt8 ] , cost: Int , salt: [ UInt8 ] ) throws -> [ UInt8 ] {
27- guard ( salt. count * 3 / 4 ) - 1 < Hasher . maxSalt else {
44+ public static func hash( password: [ UInt8 ] , cost: Int = 10 , salt: [ UInt8 ] , version : BcryptVersion = . v2b ) throws -> [ UInt8 ] {
45+ guard ( salt. count * 3 / 4 ) - 1 < Self . maxSalt else {
2846 throw BcryptError . invalidSaltLength
2947 }
3048
@@ -47,12 +65,12 @@ public struct Hasher {
4765
4866 let ( p, s) = EksBlowfish . setup ( password: password, salt: cSalt, cost: cost)
4967
50- var cData = [ UInt32] ( repeating: 0 , count: Hasher . words)
68+ var cData = [ UInt32] ( repeating: 0 , count: Self . words)
5169
5270 var i = 0
5371 var j = 0
54- while i < Hasher . words {
55- cData [ i] = EksBlowfish . stream2word ( data: Hasher . cipherText, j: & j)
72+ while i < Self . words {
73+ cData [ i] = EksBlowfish . stream2word ( data: Self . cipherText, j: & j)
5674 i &+= 1
5775 }
5876
@@ -61,7 +79,7 @@ public struct Hasher {
6179 var j = 0
6280 var xl : UInt32 = 0
6381 var xr : UInt32 = 0
64- while j < Hasher . words / 2 {
82+ while j < Self . words / 2 {
6583 xl = cData [ j * 2 ]
6684 xr = cData [ j * 2 + 1 ]
6785 EksBlowfish . encipher ( xl: & xl, xr: & xr, p: p, s: s)
@@ -72,9 +90,9 @@ public struct Hasher {
7290 i &+= 1
7391 }
7492
75- var cipherText = Hasher . cipherText
93+ var cipherText = Self . cipherText
7694 i = 0
77- while i < Hasher . words {
95+ while i < Self . words {
7896 cipherText [ 4 * i + 3 ] = UInt8 ( cData [ i] & 0xff )
7997 cipherText [ 4 * i + 2 ] = UInt8 ( ( cData [ i] &>> 8 ) & 0xff )
8098 cipherText [ 4 * i + 1 ] = UInt8 ( ( cData [ i] &>> 16 ) & 0xff )
@@ -109,15 +127,19 @@ public struct Hasher {
109127 var salt = [ UInt8] ( repeating: 0 , count: saltSpace)
110128
111129 var cSalt = [ UInt8] ( repeating: 0 , count: maxSalt)
112- for i in 0 ..< maxSalt {
130+ var i = 0
131+ while i < maxSalt {
113132 cSalt [ i] = UInt8 . random ( in: . min ... . max)
133+ i &+= 1
114134 }
115135
116136 let encodedSalt = Base64 . encode ( cSalt, count: Self . hashSpace)
117- for (i, byte) in encodedSalt. enumerated ( ) {
137+ i = 0
138+ while i < encodedSalt. count {
118139 if i < saltSpace {
119- salt [ i] = byte
140+ salt [ i] = encodedSalt [ i ]
120141 }
142+ i &+= 1
121143 }
122144
123145 return salt
0 commit comments