This repository has been archived by the owner on Nov 29, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 55
/
PasswordHasher.scala
154 lines (129 loc) · 4.6 KB
/
PasswordHasher.scala
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package tsec.passwordhashers
import java.nio.CharBuffer
import cats.{Functor, Id}
import tsec.common._
//Todo: deal with unsafe pw hashing in a more principled style
trait PasswordHasher[F[_], A] {
final def hashpw(p: String): F[PasswordHash[A]] = hashpw(p.asciiBytes)
/** Hash a password in a char array
* then clear the data in the password original
* array, as well as the byte encoding change,
* but in a pure fashion because
* side effects suck butt.
*
*/
def hashpw(p: Array[Char]): F[PasswordHash[A]]
/** Hash a password in utf-8 encoded bytes,
* then clear the data in the password,
* but in a pure way.
*
* @param p the encoded password
* @return
*/
def hashpw(p: Array[Byte]): F[PasswordHash[A]]
final def hashpwUnsafe(p: String): PasswordHash[A] = hashpwUnsafe(p.asciiBytes)
/** Hash a password in a char array
* then clear the data in the password original
* array, as well as the byte encoding change.
*
* @param p the encoded password
* @return
*/
final def hashpwUnsafe(p: Array[Char]): PasswordHash[A] = {
val charbuffer = CharBuffer.wrap(p)
val bytes = defaultCharset.encode(charbuffer).array()
val out = hashPassUnsafe(bytes)
//Clear pass
ByteUtils.zeroCharArray(p)
ByteUtils.zeroByteArray(bytes)
PasswordHash[A](out)
}
/** Hash a password in utf-8 encoded bytes,
* then clear the data in the password
*
* @param p the encoded password
* @return
*/
final def hashpwUnsafe(p: Array[Byte]): PasswordHash[A] = {
val out = PasswordHash[A](hashPassUnsafe(p))
ByteUtils.zeroByteArray(p)
out
}
/** Check against a password hash in a pure way
*
* It may raise an error for a malformed hash
*/
final def checkpwBool(p: String, hash: PasswordHash[A]): F[Boolean] =
checkpwBool(p.asciiBytes, hash)
/** Check against a password hash in a pure way
*
* It may raise an error for a malformed hash
*/
def checkpwBool(p: Array[Char], hash: PasswordHash[A]): F[Boolean]
/** Check against a password hash in a pure way
*
* It may raise an error for a malformed hash
*/
def checkpwBool(p: Array[Byte], hash: PasswordHash[A]): F[Boolean]
/** Check against a password hash in a pure way
*
* It may raise an error for a malformed hash
*/
final def checkpw(p: String, hash: PasswordHash[A])(implicit F: Functor[F]): F[VerificationStatus] =
checkpw(p.asciiBytes, hash)
/** Check against a password hash in a pure way
*
* It may raise an error for a malformed hash
*/
def checkpw(p: Array[Char], hash: PasswordHash[A])(implicit F: Functor[F]): F[VerificationStatus] =
F.map(checkpwBool(p, hash))(c => if (c) Verified else VerificationFailed)
/** Check against a password hash in a pure way
*
* It may raise an error for a malformed hash
*/
def checkpw(p: Array[Byte], hash: PasswordHash[A])(implicit F: Functor[F]): F[VerificationStatus] =
F.map(checkpwBool(p, hash))(c => if (c) Verified else VerificationFailed)
/** Check against a password hash in an unsafe
* manner.
*
* It may throw an exception for a malformed password
* @return
*/
final def checkpwUnsafe(p: String, hash: PasswordHash[A]): Boolean = checkpwUnsafe(p.asciiBytes, hash)
/** Check against a password hash in an unsafe
* manner.
*
* It may throw an exception for a malformed password
* @return
*/
final def checkpwUnsafe(p: Array[Byte], hash: PasswordHash[A]): Boolean = {
val out = checkPassUnsafe(p, hash)
//Clear pass
ByteUtils.zeroByteArray(p)
out
}
/** Check against a password hash in an unsafe
* manner.
*
* It may throw an exception for a malformed password
* @return
*/
final def checkpwUnsafe(p: Array[Char], hash: PasswordHash[A]): Boolean = {
val charbuffer = CharBuffer.wrap(p)
val bytes = defaultCharset.encode(charbuffer).array()
val out = checkPassUnsafe(bytes, hash)
//Clear pass
ByteUtils.zeroCharArray(p)
ByteUtils.zeroByteArray(bytes)
out
}
/** Internal api **/
private[tsec] def hashPassUnsafe(p: Array[Byte]): String
private[tsec] def checkPassUnsafe(p: Array[Byte], hash: PasswordHash[A]): Boolean
}
trait IdPasswordHasher[A] extends PasswordHasher[Id, A] {
def hashpw(p: Array[Char]): Id[PasswordHash[A]] = hashpwUnsafe(p)
def hashpw(p: Array[Byte]): Id[PasswordHash[A]] = hashpwUnsafe(p)
def checkpwBool(p: Array[Char], hash: PasswordHash[A]): Id[Boolean] = checkpwUnsafe(p, hash)
def checkpwBool(p: Array[Byte], hash: PasswordHash[A]): Id[Boolean] = checkpwUnsafe(p, hash)
}