Time-based one-time password algorithm: Difference between revisions
Content deleted Content added
m →{{header|Wren}}: Minor tidy and rerun |
|||
(4 intermediate revisions by 4 users not shown) | |||
Line 31:
=={{header|C sharp|C#}}==
<
using System.Security.Cryptography;
Line 92:
}
}
</syntaxhighlight>
=={{header|Caché ObjectScript}}==
<
Class Utils.Security [ Abstract ]
{
Line 182:
}
</syntaxhighlight>
{{out|Example}}
<pre>
Line 200:
=={{header|Go}}==
A slightly [https://github.com/gwwfps/onetime/pull/1 fixed] version of a [https://github.com/gwwfps/onetime package by Zitao Zhang] (released under a [https://github.com/gwwfps/onetime/blob/master/LICENSE simplified BSD license]).
<
// implementing the HOTP and TOTP algorithms as specified by IETF RFC-4226
// and RFC-6238.
Line 273:
p[0] &= 0x7f
return p
}</
{{out|Example use}}
(in a format that gets put into the [https://godoc.org/github.com/dchapes/onetime generated documentation])
<
import (
Line 314:
var code = otp.TOTP(secret)
fmt.Println(code)
}</
=={{header|J}}==
<syntaxhighlight lang="j">DA =: '0123456789ABCDEF'
to_bytes =: 16 16#.(2,~2%~#)$ DA i. ]
upper =: 1&(3!:12)
xor =: 22 b.
and =: 17 b.
hmac_sha1 =: {{
sha1 =. _1&(128!:6)
b_size =. 512 % 8
pad_key =. b_size {.]
block_sized_key =. pad_key a.&i. x
o_key_pad =. block_sized_key xor b_size $ 16b5c
i_key_pad =. block_sized_key xor b_size $ 16b36
hashed =. sha1 (i_key_pad { a.), y
a. i. sha1 (o_key_pad { a.), hashed }}
totp =: {{
h =. x hmac_sha1&:(a. {~ to_bytes&]) y
offset =. 16bf and {: h
1000000|16b7fffffff and (4$256)#. 4 {. offset |. h }}
</syntaxhighlight>
{{out|Example use}}
<syntaxhighlight lang="j">time =: '0000000000000001' NB. 64-bit timestamp in hex format
secrete =: 'AB54A98CEB1F0AD2' NB. secrete key in hex format
time totp secrete NB. 758742
</syntaxhighlight>
=={{header|Julia}}==
<
using SHA
Line 355 ⟶ 388:
sleep(15)
end
</
<pre>
656601
Line 372 ⟶ 405:
Note that due to the interface of the hash function in module “std/sha1”, we have chosen to work with sequences of characters rather than sequences of bytes. The other way is of course possible, but maybe less convenient.
<
type
Line 470 ⟶ 503:
echo "Google authenticator:"
exampleAuthenticator()</
{{out}}
Line 480 ⟶ 513:
=={{header|Perl}}==
{{trans|Raku}}
<
use strict;
Line 493 ⟶ 526:
for ( my $t = 2177452800 ; $t < 2177452919 ; $t += 13 ) {
print "At ", scalar gmtime $t, " : ", $oath->totp( $message, $t ), "\n" ;
}</
{{out}}
<pre>
Line 506 ⟶ 539:
At Sat Jan 1 00:01:44 2039 : 341623
At Sat Jan 1 00:01:57 2039 : 341623
</pre>
=={{header|Phix}}==
{{trans|Perl}}
Note the byte ordering of hmac (etc) is suspect and may change, hence bmap below
<!--<syntaxhighlight lang="phix">-->
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.1"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- sha1.e added</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">sha1</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">hmac</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">bmap</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">16</span><span style="color: #0000FF;">,</span><span style="color: #000000;">15</span><span style="color: #0000FF;">,</span><span style="color: #000000;">14</span><span style="color: #0000FF;">,</span><span style="color: #000000;">13</span><span style="color: #0000FF;">,</span><span style="color: #000000;">20</span><span style="color: #0000FF;">,</span><span style="color: #000000;">19</span><span style="color: #0000FF;">,</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span><span style="color: #000000;">17</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">dt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">hmac_result</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">offset</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hmac_result</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bmap</span><span style="color: #0000FF;">[$]],</span><span style="color: #000000;">#0F</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">*</span><span style="color: #000000;">#100</span><span style="color: #0000FF;">+</span><span style="color: #000000;">hmac_result</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bmap</span><span style="color: #0000FF;">[</span><span style="color: #000000;">offset</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7F</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">digits</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">totp</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">int_to_bytes</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">/</span><span style="color: #000000;">30</span><span style="color: #0000FF;">),</span><span style="color: #000000;">8</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">hmac_sha1</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">reverse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">dt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">timedate</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #000000;">set_timedate_formats</span><span style="color: #0000FF;">({</span><span style="color: #008000;">"Mmm dth yyyy h:mm:ss"</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">timedate</span> <span style="color: #000000;">td0</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_date_string</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Jan 1st 1970 00:00:00"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">message</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"show me the monKey"</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2177452800</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">13</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">format_timedate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">adjust_timedate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">td0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">t</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"At %s : %06d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">totp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">message</span><span style="color: #0000FF;">,</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
At Jan 1st 2039 0:00:00 : 950428
At Jan 1st 2039 0:00:13 : 950428
At Jan 1st 2039 0:00:26 : 950428
At Jan 1st 2039 0:00:39 : 361382
At Jan 1st 2039 0:00:52 : 361382
At Jan 1st 2039 0:01:05 : 022576
At Jan 1st 2039 0:01:18 : 022576
At Jan 1st 2039 0:01:31 : 341623
At Jan 1st 2039 0:01:44 : 341623
At Jan 1st 2039 0:01:57 : 341623
</pre>
=={{header|PicoLisp}}==
Using the <tt>sha1</tt> function defined at ''[[SHA-1#PicoLisp]]'':
<
(de hmac ("Fun" Msg Key)
Line 563 ⟶ 647:
(test
(cdr L)
(totp (mapcar char (chop "12345678901234567890")) (car L) 8) ) )</
=={{header|Racket}}==
This includes BASE32 encoding, token based authentication and other such stuff.
<
(require (only-in web-server/stuffers/hmac-sha1 HMAC-SHA1))
Line 711 ⟶ 795:
(base32-encode-bytes #"Super Secret Password Key 88!")
=> #"KN2XAZLSEBJWKY3SMV2CAUDBONZXO33SMQQEWZLZEA4DQII="
))</
{{out}}
Line 729 ⟶ 813:
(formerly Perl 6)
This is a minimal attempt that covers only the "Time-based" part of the requirement.
<syntaxhighlight lang="raku"
# https://github.com/retupmoca/P6-Digest-HMAC
Line 752 ⟶ 836:
say totp $message, DateTime.new(now);
}
</syntaxhighlight>
{{out}}
<pre>Deterministic output at 2039-01-01T00:00:00Z with fixed checks,
Line 773 ⟶ 857:
This TOTP/HOTP module clocks in small by taking advantage of [https://core.tcl.tk/tcllib/doc/trunk/embedded/www/toc.html tcllib's] existing hashing and base32 modules.
<syntaxhighlight lang="tcl">
# rfc6238 contains examples of hotp with 8-digit modulus and sha1/sha256/sha512 hmac
#
Line 844 ⟶ 928:
}
assert {{306281 553572 304383} eq [google 1400000000]}
}</
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-long}}
{{libheader|Wren-crypto}}
{{libheader|Wren-date}}
{{libheader|Wren-srandom}}
As Wren-cli currently has no way of determining the Unix time, this needs to be input as a command line parameter so we can track it from there.
<syntaxhighlight lang="wren">import "os" for Process
import "./long" for ULong
import "./crypto" for Bytes, Sha1, Sha256, Hmac
import "./date" for Date
import "./srandom" for SRandom
var StartTime = null // time program was started (as a Unix timestamp)
class OneTimePassword {
construct new(digit, timeStep, baseTime, hashClass) {
_digit = digit // length of code generated
_timeStep = timeStep // length of each time step for TOTP
_baseTime = baseTime // start time for TOTP step calculation (as a Unix timestamp)
_hashClass = hashClass // hash class to be used with HMAC
}
// Convenience version of above which uses defaults values for all except 'digit' parameter.
static simple(digit) { new(digit, 30, 0, Sha1) }
// Returns a HOTP code with the given secret and counter.
hotp(secret, count) { truncate_(hmacSum_(secret, count)) }
// Returns a TOTP code calculated with the current time and the given secret.
totp(secret) { hotp(secret, steps_(timeNow_)) }
/* private helper methods */
hmacSum_(secret, count) {
var msg = ULong.new(count).toBytes[-1..0] // big-endian
return Bytes.fromHexString(Hmac.digest(secret, msg, Sha1))
}
dt_(hs) {
var offset = hs[-1] & 0xf
var p = hs[offset...offset+4]
p[0] = p[0] & 0x7f
return p
}
truncate_(hs) {
var sbits = dt_(hs)
var snum = Bytes.toIntBE(sbits)
var pwr = 10.pow(_digit)
return snum % pwr
}
steps_(now) { ((now - _baseTime)/_timeStep).floor }
timeNow_ { (StartTime + System.clock).floor }
}
var args = Process.arguments
if (args.count != 1) {
System.print("Please pass the Unix timestamp when starting the program.")
return
}
StartTime = Num.fromString(args[0])
var secret = "SOME_SECRET".bytes.toList
// Simple 6-digit HOTP code.
var otp = OneTimePassword.simple(6)
System.print(otp.hotp(secret, 123456))
// Google authenticator style 8-digit TOTP code.
otp = OneTimePassword.simple(8)
System.print(otp.totp(secret))
// Custom 9 digit, 5 second step TOTP starting on midnight 2000-01-01 UTC, using Sha256.
var baseTime = Date.new(2000, 1, 1).unixTime
otp = OneTimePassword.new(9, 5, baseTime, Sha256)
System.print(otp.totp(secret))
// As above using a random, 32 byte, Base32 key
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" // for Base32
var randKey = List.filled(32, null)
for (i in 0..31) randKey[i] = alphabet[SRandom.int(32)]
System.print(otp.totp(randKey.join().bytes.toList))</syntaxhighlight>
{{out}}
Sample output:
<pre>
$ date '+%s'
1707913906
$ wren-cli Time-based_one-time_password_algorithm.wren 1707913906
260040
38559208
185760458
556237229
</pre>
=={{header|zkl}}==
Uses the MsgHash dll, which includes SHA-1, SHA-256 hashes and HMAC routines for SHA-* and MD5.
{{trans|Go}}
<
// OneTimePassword stores the configuration values relevant to HOTP/TOTP calculations.
Line 885 ⟶ 1,066:
fcn totp(secret){ hotp(secret, steps(Time.Clock.time())) }
fcn steps(now) { (now - baseTime)/timeStep } // elapsed time chunked
} // OneTimePassword</
Note: MsgHash hashes return a string by default, they can also return the hash as bytes. Ditto the HMAC routines, it is the third parameter. So, to create a hmac that returns bytes, use (eg) MsgHash.extra.hmacSHA1.fp2(False), this creates a partial application (closure) of the hmac using SHA-1 fixing the third parameter as False.
{{out|Example uses}}
<
// Simple 6-digit HOTP code:
secret := "SOME_SECRET";
Line 913 ⟶ 1,094:
code := otp.totp(secret);
println(code) //-->eg 707355416
}();</
{{out|Example use}}
Showing how to sync with changes over time. A six digit OTP w/MD5 changing every 17 seconds. Latency can effect the result when totp is called at a time boundary, so a retry may be required.
<
secret,ts:= "SOME_SECRET",17;
otp := OneTimePassword(6,ts,Time.Clock.time(),MsgHash.extra.hmacMD5.fp2(False));
Line 926 ⟶ 1,107:
Atomic.sleep(10);
}
}</
{{out}}
<pre>
Line 943 ⟶ 1,124:
{{out|HMAC code}}
The MsgHash HMAC routines are pretty simple (the hash code is C), included here for completeness:
<
fcn hmac(key,msg,hashFcn,asString){
blkSz,H,Hx := 64,hashFcn.fp1(1,Data()), (asString and hashFcn or H);
Line 956 ⟶ 1,137:
fcn hmacSHA1( key,msg,asString=True){ hmac(key,msg,MsgHash.SHA1, asString) }
fcn hmacSHA256(key,msg,asString=True){ hmac(key,msg,MsgHash.SHA256,asString) }
fcn hmacMD5( key,msg,asString=True){ hmac(key,msg,Utils.MD5.calc,asString) }</
|