otp 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8cbd2209dffb82f3c54afdea2346ad7e0ed260d2
4
- data.tar.gz: e7383b28e5878069abc456c608bf14544ab49fd1
3
+ metadata.gz: 0c73f2c47bcd8a1d4b36391d5b8ffd77fee13670
4
+ data.tar.gz: 29c50f0d362b6abd5d018c69301f919dfffc748c
5
5
  SHA512:
6
- metadata.gz: c471ff52aca2b750dd641308eeac8a8891f969506442e60cc1d9bd659bae4a68a067e51c765976215ecfdb68342869d3d102f9b25731ed8b7ab0623cbfd7df25
7
- data.tar.gz: 877c4ec9abcc75191a1c5af5a04ff7965db08b43b7ffa7b9959abdf1d5f5f2899e13eeea7894e10d1881dcdc777cc89e43114514309acd3950ed9b0244787fa7
6
+ metadata.gz: 234d1455ead02f326578c8a2470586eb056c8c91ace926476ff384e53843ef1a58481d015e8dc05442b6830834703cb1b5205344cdca6e9aa7ad7e1df9204b0b
7
+ data.tar.gz: cd3df6b91c9fb94f138646913aa6a3efdaa8988e0c3a96fb3b0dd58a3a9d32065425c932226cafad893d22fec14565997b2b4a92f76a0d30995498a4597820e5
data/.gitignore CHANGED
@@ -19,4 +19,5 @@ tmp
19
19
  *.so
20
20
  *.o
21
21
  *.a
22
+ *.swp
22
23
  mkmf.log
data/README.md CHANGED
@@ -4,13 +4,8 @@
4
4
  [![Gem Version](https://badge.fury.io/rb/otp.svg)](https://rubygems.org/gems/otp)
5
5
  [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/gotoyuzo/otp/blob/master/LICENSE.txt)
6
6
 
7
- This library provides an implementation of
8
- HMAC-Based One-Time Password Algorithm (HOTP; RFC4226) and
7
+ This library provides an implementation of HMAC-Based One-Time Password Algorithm (HOTP; RFC4226) and
9
8
  Time-Based One-Time Password Algorithm (HOTP; RFC6238).
10
- The Algorithm details can be referred at the following URLs.
11
-
12
- * HOTP: http://tools.ietf.org/html/rfc4226
13
- * TOTP: http://tools.ietf.org/html/rfc6238
14
9
 
15
10
  ## Usage
16
11
 
@@ -43,8 +38,20 @@ To verify given TOTP password:
43
38
  totp.secret = "YVMR2G7N4OAXGKFC"
44
39
  p totp.verify("123456") #=> true/false (verify given passowrd)
45
40
 
46
- The value of "secret" is encoded with BASE32 algorithm to be compatible
47
- with Google Authenticator URI format.
41
+ You can use the last and post option parameters to verify several generations, including before and after the current password.
42
+
43
+ # verify passwords from last 2 generation to post 1 generation
44
+ p totp.verify("123456", last: 2, post: 1)
45
+
46
+ ## Related Information
47
+
48
+ TOTP and HOTP algorithm details can be referred at the following URLs.
49
+
50
+ * HOTP: An HMAC-Based One-Time Password Algorithm - http://tools.ietf.org/html/rfc4226
51
+ * TOTP: Time-Based One-Time Password Algorithm - http://tools.ietf.org/html/rfc6238
52
+
53
+ In the OTP URI format, the value of "secret" is encoded with BASE32 algorithm.
54
+ The Format details are described in the document of Google Authenticator.
48
55
 
49
- * BASE32: http://tools.ietf.org/html/rfc4648
50
- * Google Authenticator Key URI format: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
56
+ * The Base16, Base32, and Base64 Data Encodings - http://tools.ietf.org/html/rfc4648
57
+ * Google Authenticator Key URI format - https://github.com/google/google-authenticator/wiki/Key-Uri-Format
@@ -1,11 +1,11 @@
1
1
  module OTP
2
2
  module Base32
3
- BASE32_ENCODE = %w(
3
+ ENCODE_CHARS = %w(
4
4
  A B C D E F G H I J K L M N O P
5
5
  Q R S T U V W X Y Z 2 3 4 5 6 7
6
6
  )
7
7
 
8
- BASE32_DECODE = {
8
+ DECODE_MAP = {
9
9
  ?A=>0, ?B=>1, ?C=>2, ?D=>3, ?E=>4, ?F=>5, ?G=>6, ?H=>7,
10
10
  ?I=>8, ?J=>9, ?K=>10, ?L=>11, ?M=>12, ?N=>13, ?O=>14, ?P=>15,
11
11
  ?Q=>16, ?R=>17, ?S=>18, ?T=>19, ?U=>20, ?V=>21, ?W=>22, ?X=>23,
@@ -13,23 +13,35 @@ module OTP
13
13
  ?==>-1,
14
14
  }
15
15
 
16
+ DECODE_LENGTH = {
17
+ 1 => 1, # 5 bits -> 1 byte (irregular)
18
+ 2 => 1, # 10 bits -> 1 byte
19
+ 3 => 2, # 15 bits -> 2 bytes (irregular)
20
+ 4 => 2, # 20 bits -> 2 bytes
21
+ 5 => 3, # 25 bits -> 3 bytes
22
+ 6 => 4, # 30 bits -> 4 bytes (irregular)
23
+ 7 => 4, # 35 bits -> 4 bytes
24
+ 8 => 5, # 40 bits -> 5 bytes
25
+ }
26
+
16
27
  module_function
17
28
 
18
- def encode(bytes)
29
+ def encode(bytes, padding: true)
19
30
  return nil unless bytes
31
+ pad = padding ? ?= : ""
20
32
  ret = ""
21
33
  bytes = bytes.dup.force_encoding("binary")
22
34
  off = 0
23
35
  while off < bytes.length
24
36
  n = 0
25
37
  bits = bytes[off, 5]
26
- l = bits.length
38
+ off += 5
39
+ l = (bits.length * 8.0 / 5.0).ceil
27
40
  bits << "\0" while bits.length < 5
28
41
  bits.each_byte{|b| n = (n << 8) | b }
29
- 8.times do |i|
30
- ret << ((l*8/5 < i) ? ?= : BASE32_ENCODE[(n >> (7-i)*5) & 0x1f])
42
+ (1..8).each do |i|
43
+ ret << ((i > l) ? pad : ENCODE_CHARS[(n >> (8-i)*5) & 0x1f])
31
44
  end
32
- off += 5
33
45
  end
34
46
  return ret
35
47
  end
@@ -43,18 +55,24 @@ module OTP
43
55
  while off < chars.length
44
56
  n = l = 0
45
57
  bits = chars[off, 8]
58
+ off += 8
46
59
  bits << "=" while bits.length < 8
47
60
  bits.each_char.with_index do |c, i|
48
- d = BASE32_DECODE[c]
49
- raise ArgumentError, "invalid char: #{c}" unless d
50
- n <<= 5
51
- if d >= 0
61
+ d = DECODE_MAP[c]
62
+ if d.nil?
63
+ raise ArgumentError, "invalid char: #{c}"
64
+ elsif d < 0
65
+ n <<= 5 * (8-i)
66
+ off = chars.length
67
+ break
68
+ else
69
+ n <<= 5
52
70
  n |= d
53
- l = i * 5 / 8
71
+ l = ((i+1) * 5.0 / 8.0).floor
72
+ l = DECODE_LENGTH[i+1]
54
73
  end
55
74
  end
56
- ret << (0..l).map{|i| (n >> 32 - i * 8) & 0xff }.pack("c*")
57
- off += 8
75
+ ret << (1..l).map{|i| (n >> 40 - i * 8) & 0xff }.pack("c*")
58
76
  end
59
77
  return ret
60
78
  end
@@ -1,4 +1,4 @@
1
1
  module OTP
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
4
4
 
@@ -2,8 +2,8 @@ require "test/unit"
2
2
  require "otp/base32"
3
3
 
4
4
  class TestBase32 < Test::Unit::TestCase
5
- def assert_encode(encoded, plain)
6
- assert_equal(encoded, ::OTP::Base32.encode(plain))
5
+ def assert_encode(encoded, plain, padding: true)
6
+ assert_equal(encoded, ::OTP::Base32.encode(plain, padding: padding))
7
7
  end
8
8
 
9
9
  def assert_decode(plain, encoded)
@@ -11,9 +11,9 @@ class TestBase32 < Test::Unit::TestCase
11
11
  assert_equal(plain, ::OTP::Base32.decode(encoded))
12
12
  end
13
13
 
14
- def assert_encode_decode(plain, encoded)
14
+ def assert_encode_decode(plain, encoded, padding: true)
15
15
  assert_decode(plain, encoded)
16
- assert_encode(encoded, plain)
16
+ assert_encode(encoded, plain, padding: padding)
17
17
  end
18
18
 
19
19
  def test_base32
@@ -28,6 +28,18 @@ class TestBase32 < Test::Unit::TestCase
28
28
  assert_encode_decode("\u{3042}\u{3044}\u{3046}\u{3048}\u{304a}", "4OAYFY4BQTRYDBXDQGEOHAMK")
29
29
  end
30
30
 
31
+ def test_base32_without_padding
32
+ assert_encode_decode(nil, nil, padding: false)
33
+ assert_encode_decode("", "", padding: false)
34
+ assert_encode_decode("f", "MY", padding: false)
35
+ assert_encode_decode("fo", "MZXQ", padding: false)
36
+ assert_encode_decode("foo", "MZXW6", padding: false)
37
+ assert_encode_decode("foob", "MZXW6YQ", padding: false)
38
+ assert_encode_decode("fooba", "MZXW6YTB", padding: false)
39
+ assert_encode_decode("foobar", "MZXW6YTBOI", padding: false)
40
+ assert_encode_decode("\u{3042}\u{3044}\u{3046}\u{3048}\u{304a}", "4OAYFY4BQTRYDBXDQGEOHAMK", padding: false)
41
+ end
42
+
31
43
  def test_truncated_decode
32
44
  assert_decode("f", "MY")
33
45
  assert_decode("fo", "MZXQ")
@@ -38,4 +50,23 @@ class TestBase32 < Test::Unit::TestCase
38
50
  assert_decode("foo", "mzxw6")
39
51
  assert_decode("foob", "mzxw6yq")
40
52
  end
53
+
54
+ def test_unspecified
55
+ assert_raise(ArgumentError){ OTP::Base32.decode("MY0") }
56
+ assert_decode("", "=")
57
+ assert_decode("`", "M=======")
58
+ assert_decode("fn", "MZX=====")
59
+ assert_decode("foo`", "MZXW6Y==")
60
+ assert_decode("`", "M=======G")
61
+ assert_decode("fn", "MZX=====G")
62
+ assert_decode("foo`", "MZXW6Y==G")
63
+ assert_decode("`", "M")
64
+ assert_decode("fn", "MZX")
65
+ assert_decode("foo`", "MZXW6Y")
66
+ assert_decode("fooba", "MZXW6YTB===")
67
+ assert_decode("f", "MY=AAAAA")
68
+ assert_decode("fo", "MZXQ=AAA")
69
+ assert_decode("foo", "MZXW6=AA")
70
+ assert_decode("foo", "MZXW6=00")
71
+ end
41
72
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: otp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuuzou Gotou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-05 00:00:00.000000000 Z
11
+ date: 2015-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler