在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):marcelkliemannel/kotlin-onetimepassword开源软件地址(OpenSource Url):https://github.com/marcelkliemannel/kotlin-onetimepassword开源编程语言(OpenSource Language):Kotlin 100.0%开源软件介绍(OpenSource Introduction):Kotlin One-Time Password LibraryThis is a Kotlin library to generate one-time password codes for:
The implementations are based on the RFCs:
DependencyThis library is available at Maven Central: Gradle// Groovy
implementation 'dev.turingcomplete:kotlin-onetimepassword:2.2.0'
// Kotlin
implementation("dev.turingcomplete:kotlin-onetimepassword:2.2.0") Maven<dependency>
<groupId>dev.turingcomplete</groupId>
<artifactId>kotlin-onetimepassword</artifactId>
<version>2.2.0</version>
</dependency> UsageGeneral Flow
ImplementationThe client of the user and the server must use the same code generator with the same configuration (e.g., number of code digits, hash algorithm). If the one-time-password is used for two-factor authentication, a possible HTTP flow could look like this (even if it does not follow an official standardization):
Number of Code DigitsAll three one-time password generators create a code value with a fixed length given by the code digits property in the configuration instance. The computed code gets filled with zeros at the beginning to meet this requirement. This filling is the reason why the code gets represented as a String. The RFC 4226 requires a code digits value between 6 and 8 to assure a good security trade-off. However, this library does not set any requirements for this property. But notice that through the design of the algorithm, the maximum code value is 2,147,483,647. This maximum value means that a higher code digits value than ten adds more trailing zeros to the code (in the case of 10 digits, the first number is always 0, 1, or 2). HMAC-based One-time Password (HOTP)The HOTP generator is available through the class val secret = "Leia"
val config = HmacOneTimePasswordConfig(codeDigits = 8,
hmacAlgorithm = HmacAlgorithm.SHA1)
val hmacOneTimePasswordGenerator = HmacOneTimePasswordGenerator(secret.toByteArray(), config) The configuration instance takes the number of code digits to be generated (see the previous chapter) and the HMAC algorithm to be used (SHA1, SHA256, and SHA512 are available). The method var code0: String = hmacOneTimePasswordGenerator.generate(counter = 0)
var code1: String = hmacOneTimePasswordGenerator.generate(counter = 1)
var code2: String = hmacOneTimePasswordGenerator.generate(counter = 2)
... There is also a helper method Time-based One-time Password (TOTP)The TOTP generator is available through the class val secret = "Leia"
val config = TimeBasedOneTimePasswordConfig(codeDigits = 8,
hmacAlgorithm = HmacAlgorithm.SHA1,
timeStep = 30,
timeStepUnit = TimeUnit.SECONDS)
val timeBasedOneTimePasswordGenerator = TimeBasedOneTimePasswordGenerator(secret.toByteArray(), config) As well as the HOTP configuration, the TOTP configuration takes the number of code digits and the HMAC algorithm as arguments (see the previous chapter). Additionally, the time window in which the generated code is valid is represented through the arguments timeStep and time step unit. The default value of the timestamp is the current system time The methods var code0: String = timeBasedOneTimePasswordGenerator.generate() // Will use System.currentTimeMillis()
var code1: String = timeBasedOneTimePasswordGenerator.generate(timestamp = 1622234248000L)
var code2: String = timeBasedOneTimePasswordGenerator.generate(date = java.util.Date(59)) // Will internally call generate(timestamp = date.time)
var code3: String = timeBasedOneTimePasswordGenerator.generate(instant = java.time.Instant.ofEpochSecond(1622234248L)) // Will internally call generate(timestamp = instante.toEpochMillis())
... Again, there is a helper method There is also a helper method for calculating the time slot (counter) from a given timestamp, var counter0: Long = timeBasedOneTimePasswordGenerator.counter() // Will use System.currentTimeMillis()
var counter1: Long = timeBasedOneTimePasswordGenerator.counter(timestamp = 1622234248000L)
var counter2: Long = timeBasedOneTimePasswordGenerator.counter(date = java.util.Date(59)) // Will internally call counter(timestamp = date.time)
var counter3: Long = timeBasedOneTimePasswordGenerator.counter(instant = java.time.Instant.ofEpochSecond(1622234248L)) // Will internally call counter(timestamp = instante.toEpochMillis())
... You can use this counter to calculate the start and the end of a timeslot and with this how long your TOTP is still valid. val timestamp = instant.toEpochMillis()
val totp = timeBasedOneTimePasswordGenerator.generate(timestamp)
val counter = timeBasedOneTimePasswordGenerator.counter()
val startEpochMillis = timeBasedOneTimePasswordGenerator.timeslotStart(counter)
//basically the start of next time slot minus 1ms
val endEpochMillis = timeBasedOneTimePasswordGenerator.timeslotStart(counter+1)-1
//number of milliseconds the current TOTP is still valid
val millisValid = endEpochMillis - timestamp Google AuthenticatorThe "Google Way"Some TOTP generators use the "Google way" to generate codes. This slightly different behavior means that the generator works internally with the plain text secret, but the secret gets passed around as Base32-encoded. (Confusing the plain text and the Base32-encoded secret in the different steps is the most common reason people think the Google Authenticator with this library doesn't work.) The Google Authenticator generator is available through the class // Warning: the length of the plain text may be limited, see next chapter
val plainTextSecret = "Secret1234".toByteArray(Charsets.UTF_8)
// This is the encoded one to use in most of the generators (Base32 is from the Apache commons codec library)
val base32EncodedSecret = Base32().encodeToString(plainTextSecret)
println("Base32 encoded secret to be used in the Google Authenticator app: $base32EncodedSecret")
val googleAuthenticator = GoogleAuthenticator(secret = base32EncodedSecret)
var code = googleAuthenticator.generate() // Will use System.currentTimeMillis() See the TOTP generator for the code generation There is also a helper method Secret Length LimitationSome generators limit the length of the plain text secret or set a fixed number of characters. So the "Google way", which has a fixed value of 10 characters. Anything outside this range will not be handled correctly by some generators. QR CodeQR codes must use a URI that follows the definition in Key Uri Format. The secret in this URI is the Base32-encoded one. Simulate the Google AuthenticatorThe directory Alternatively, you can use the following code to simulate the Google Authenticator on the command line. It prints a valid code for the secret fun main() {
val base32Secret = "K6IPBHCQTVLCZDM2"
Timer().schedule(object: TimerTask() {
override fun run() {
val timestamp = Date(System.currentTimeMillis())
val code = GoogleAuthenticator(base32Secret).generate(timestamp)
println("${SimpleDateFormat("HH:mm:ss").format(timestamp)}: $code")
}
}, 0, 1000)
} Random Secret GeneratorRFC 4226 recommends using a secret of the same length as the hash produced by the HMAC algorithm. The class val randomSecretGenerator = RandomSecretGenerator()
val secret0: ByteArray = randomSecretGenerator.createRandomSecret(HmacAlgorithm.SHA1) // 20-byte secret
val secret1: ByteArray = randomSecretGenerator.createRandomSecret(HmacAlgorithm.SHA256) // 32-byte secret
val secret2: ByteArray = randomSecretGenerator.createRandomSecret(HmacAlgorithm.SHA512) // 64-byte secret
val secret3: ByteArray = randomSecretGenerator.createRandomSecret(1234) // 1234-byte secret LicensingCopyright (c) 2022 Marcel Kliemannel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE for the specific language governing permissions and limitations under the License. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论