sirp 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'puma'
4
+ gem 'sinatra'
5
+ gem 'http'
6
+ gem 'sirp', path: '../'
@@ -0,0 +1,34 @@
1
+ # SiRP : Secure (interoperable) Remote Password : Example
2
+
3
+ ## Install Ruby Dependencies
4
+
5
+ ```
6
+ $ cd examples
7
+ $ bundle install
8
+ ```
9
+
10
+ ## Run Server
11
+
12
+ ```sh
13
+ # run this in the first terminal window
14
+ $ ./server.rb
15
+ ```
16
+
17
+ ## Authenticate with Ruby Client
18
+
19
+ ```sh
20
+ # run this in the second terminal window
21
+ $ cd clients/ruby/
22
+ $ ./client.rb
23
+ ```
24
+
25
+ ## Authenticate with JavaScript Client
26
+
27
+ ```sh
28
+ # see the output of the JS client in the browser's JS console
29
+ $ cd clients/javascript/
30
+ $ npm install
31
+ $ open index.html
32
+ ```
33
+
34
+ You can find other username : password combinations in `server.rb`
@@ -0,0 +1 @@
1
+ /node_modules/
@@ -0,0 +1,59 @@
1
+ var client = new jsrp.client()
2
+ var serverAddr = 'http://localhost:4567/authenticate'
3
+ var username = 'leonardo'
4
+ var password = 'capricciosa'
5
+
6
+ $(document).ready(function () {
7
+ 'use strict'
8
+
9
+ console.log('Starting Authentication')
10
+
11
+ $(document).ajaxError(function (event, request, settings) {
12
+ console.log(event)
13
+ console.log(request)
14
+ console.log(settings)
15
+ })
16
+
17
+ client.init({ username: username, password: password, length: 4096 }, function () {
18
+ client.createVerifier(function (err, result) {
19
+ // result will contain the necessary values the server needs to
20
+ // authenticate this user in the future.
21
+ // sendSaltToServer(result.salt)
22
+ // sendVerifierToServer(result.verifier)
23
+
24
+ if (err) {
25
+ console.log(err.stack);
26
+ }
27
+
28
+ var A = client.getPublicKey()
29
+
30
+ // Auth Phase 1
31
+ console.log('P1 : Sending username and A to server')
32
+ $.post(serverAddr, { username: username, A: A }, function (data) {
33
+ console.log('P1 : Received salt : ', data.salt)
34
+ console.log('P1 : Received B : ', data.B)
35
+ client.setSalt(data.salt)
36
+ client.setServerPublicKey(data.B)
37
+
38
+ var clientM = client.getProof()
39
+ console.log('P1 : calculated client M : ', clientM)
40
+
41
+ // Auth Phase 2
42
+ console.log('P2 : Sending username and M to server')
43
+ $.post(serverAddr, { username: username, M: clientM }, function (data) {
44
+ console.log('P2 : Received server H_AMK : ', data.H_AMK)
45
+ if (client.checkServerProof(data.H_AMK)) {
46
+ console.log('P2 : Client and server H_AMK match. Authenticated!')
47
+ console.log('P2 : Client and server negotiated shared key K : ', client.getSharedKey())
48
+ $('#status').html('Authenticated!')
49
+ $('#username').html(username)
50
+ $('#K').html(client.getSharedKey())
51
+ } else {
52
+ $('#status').html('Authenticated FAILED')
53
+ console.log('P2 : Client and server H_AMK DO NOT match. Authentication failed!')
54
+ }
55
+ }, 'json')
56
+ }, 'json')
57
+ })
58
+ })
59
+ })
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Secure Remote Password JS Client Example</title>
6
+ </head>
7
+ <body>
8
+ <h1>Secure Remote Password JS Client Example</h1>
9
+
10
+ <p>
11
+ Open the JavaScript console to see more output. Any shared secret
12
+ negotiated on successful authentication will be displayed below.
13
+ </p>
14
+
15
+ <p id='status'></p>
16
+ <p id='username'></p>
17
+ <p id='K'></p>
18
+
19
+ <script type="text/javascript" src="node_modules/jquery/dist/jquery.min.js"></script>
20
+ <script type="text/javascript" src="node_modules/jsrp/jsrp-browser.js"></script>
21
+ <script type="text/javascript" src="app.js"></script>
22
+ </body>
23
+ </html>
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "javascript",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "app.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "",
10
+ "license": "New BSD",
11
+ "dependencies": {
12
+ "jquery": "^2.2.3",
13
+ "jsrp": "^0.2.0"
14
+ }
15
+ }
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+ require 'http'
7
+ require 'json'
8
+ require 'sirp'
9
+ require 'logger'
10
+ logger = Logger.new $stdout
11
+
12
+ server_addr = 'http://localhost:4567/authenticate'
13
+ username = 'leonardo'
14
+ password = 'capricciosa'
15
+ prime_length = 4096
16
+
17
+ # The salt and verifier should be stored on the server database.
18
+ # In this example code these values are hard-coded in server.rb
19
+ # @auth = SIRP::Verifier.new(prime_length).generate_userauth(username, password)
20
+ # @auth is a hash containing :username, :verifier and :salt
21
+
22
+ logger.info 'Start authentication'
23
+
24
+ client = SIRP::Client.new(prime_length)
25
+ A = client.start_authentication
26
+
27
+ logger.info "Sending username: '#{username}' and A: '#{A}' to server"
28
+
29
+ # Client => Server: username, A
30
+ # Server => Client: salt, B
31
+ response = HTTP.post(server_addr, form: { username: username, A: A }).parse
32
+ logger.info "Server responded with: '#{response}'"
33
+
34
+ logger.info 'Client is calculating M, from B and salt, as a response to the challenge'
35
+ client_M = client.process_challenge(username, password, response['salt'], response['B'])
36
+
37
+ # Client => Server: username, M
38
+ # Server => Client: H(AMK)
39
+ logger.info "Client is sending M: '#{client_M}' to server"
40
+ response = HTTP.post(server_addr, form: { username: username, M: client_M }).parse
41
+ logger.info "Server responded with: #{response}"
42
+
43
+ if client.verify(response['H_AMK'])
44
+ logger.info 'Client verification of server H_AMK has succeeded! Authenticated!'
45
+ logger.info "Client and server have negotiated shared secret K: '#{client.K}'"
46
+ else
47
+ logger.error 'Client verification of server H_AMK has failed!'
48
+ end
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+ require 'sinatra'
7
+ require 'json'
8
+ require 'sirp'
9
+ require 'logger'
10
+ logger = Logger.new $stdout
11
+
12
+ # Sinatra : Use Puma
13
+ configure { set :server, :puma }
14
+
15
+ # Set prime N length - client has to use the same value!
16
+ prime_length = 4096
17
+
18
+ # Simulated DB
19
+ users = {
20
+ leonardo: 'capricciosa',
21
+ raphael: 'quattro formaggi',
22
+ donatello: 'margherita',
23
+ michelangelo: 'tropicana'
24
+ }
25
+
26
+ user_verifiers = users.map do |username, password|
27
+ { username => SIRP::Verifier.new(prime_length).generate_userauth(username, password) }
28
+ end
29
+
30
+ user_verifiers.each { |h| users.update h }
31
+
32
+ before do
33
+ content_type 'application/json'
34
+ response['Access-Control-Allow-Origin'] = '*'
35
+ end
36
+
37
+ post '/authenticate' do
38
+ username = params[:username]
39
+ user = users[username.to_sym]
40
+
41
+ unless user
42
+ logger.warn "User #{username} not found"
43
+ halt 401
44
+ end
45
+
46
+ if params[:A]
47
+ logger.info 'P1 : Starting'
48
+ logger.info "P1 : Server received username '#{username}' and A"
49
+ logger.info "P1 : Client A : #{params[:A]}"
50
+ aa = params[:A]
51
+ v = user[:verifier]
52
+ salt = user[:salt]
53
+
54
+ # Server generates B, saves A and B to database
55
+ verifier = SIRP::Verifier.new(prime_length)
56
+ session = verifier.get_challenge_and_proof(username, v, salt, aa)
57
+
58
+ logger.info 'P1 : Server persisting user verifier (proof)'
59
+ user[:session_proof] = session[:proof]
60
+
61
+ logger.info 'P1 : Server sending salt and B'
62
+ logger.info "P1 : Server salt : #{session[:challenge][:salt].length} : #{session[:challenge][:salt]}"
63
+ logger.info "P1 : Server B : #{session[:challenge][:B].length} : #{session[:challenge][:B]}"
64
+ return JSON.generate(session[:challenge])
65
+ elsif params[:M]
66
+ logger.info 'P2 : Starting'
67
+ logger.info "P2 : Server received username '#{username}' and client M"
68
+ client_M = params[:M]
69
+ logger.info "P2 : Client M : #{client_M.length} : #{client_M}"
70
+
71
+ logger.info 'P2 : Retrieving verifier from the database'
72
+ proof = user[:session_proof]
73
+
74
+ logger.info 'P2 : Verifying client/server M match, generating H_AMK'
75
+ verifier = SIRP::Verifier.new(prime_length)
76
+ server_H_AMK = verifier.verify_session(proof, client_M)
77
+ logger.info "P2 : server M: #{verifier.M}"
78
+
79
+ if server_H_AMK
80
+ logger.info "P2 : #{username} Authenticated!"
81
+ logger.info "P2 : Client and server negotiated shared key K : #{verifier.K}"
82
+ logger.info "P2 : Server sending final H_AMK : #{server_H_AMK.length} : #{server_H_AMK}"
83
+ return JSON.generate(H_AMK: server_H_AMK)
84
+ end
85
+ end
86
+
87
+ halt 401
88
+ end
@@ -0,0 +1,8 @@
1
+ require 'openssl'
2
+ require 'digest'
3
+ require 'rbnacl/libsodium'
4
+ require 'securer_randomer'
5
+ require 'sirp/sirp'
6
+ require 'sirp/client'
7
+ require 'sirp/verifier'
8
+ require 'sirp/version'
@@ -0,0 +1,50 @@
1
+ module SIRP
2
+ class Client
3
+ attr_reader :N, :g, :k, :a, :A, :S, :K, :M, :H_AMK, :hash
4
+
5
+ def initialize(group = 2048)
6
+ # select modulus (N) and generator (g)
7
+ @N, @g, @hash = SIRP.Ng(group)
8
+ @k = SIRP.calc_k(@N, @g, hash)
9
+ end
10
+
11
+ def start_authentication
12
+ # Generate a/A private and public components
13
+ @a ||= SecureRandom.hex(32).hex
14
+ @A = SIRP.num_to_hex(SIRP.calc_A(@a, @N, @g))
15
+ end
16
+
17
+ # Process initiated authentication challenge.
18
+ # Returns M if authentication is successful, false otherwise.
19
+ # Salt and B should be given in hex.
20
+ def process_challenge(username, password, xsalt, xbb)
21
+ bb = xbb.to_i(16)
22
+
23
+ # SRP-6a safety check
24
+ return false if (bb % @N) == 0
25
+
26
+ x = SIRP.calc_x(username, password, xsalt, hash)
27
+ u = SIRP.calc_u(@A, xbb, @N, hash)
28
+
29
+ # SRP-6a safety check
30
+ return false if u == 0
31
+
32
+ # calculate session key
33
+ @S = SIRP.num_to_hex(SIRP.calc_client_S(bb, @a, @k, x, u, @N, @g))
34
+ @K = SIRP.sha_hex(@S, hash)
35
+
36
+ # calculate match
37
+ @M = SIRP.calc_M(@A, xbb, @K, hash)
38
+
39
+ # calculate verifier
40
+ @H_AMK = SIRP.num_to_hex(SIRP.calc_H_AMK(@A, @M, @K, hash))
41
+
42
+ @M
43
+ end
44
+
45
+ def verify(server_HAMK)
46
+ return false unless @H_AMK
47
+ @H_AMK == server_HAMK
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,283 @@
1
+ module SIRP
2
+ class << self
3
+ # http://stackoverflow.com/questions/3772410/convert-a-string-of-0-f-into-a-byte-array-in-ruby
4
+ def hex_to_bytes(str)
5
+ [str].pack('H*').unpack('C*')
6
+ end
7
+
8
+ def sha_hex(h, hash_klass)
9
+ hash_klass.hexdigest([h].pack('H*'))
10
+ end
11
+
12
+ def sha_str(s, hash_klass = Digest::SHA1)
13
+ hash_klass.hexdigest(s)
14
+ end
15
+
16
+ # Modular Exponentiation
17
+ # https://en.m.wikipedia.org/wiki/Modular_exponentiation
18
+ # http://rosettacode.org/wiki/Modular_exponentiation#Ruby
19
+ #
20
+ # a^b (mod m)
21
+ def mod_exp(a, b, m)
22
+ # Use OpenSSL::BN#mod_exp
23
+ a.to_bn.mod_exp(b, m)
24
+ end
25
+
26
+ # Hashing function with padding.
27
+ # Input is prefixed with 0 to meet N hex width.
28
+ def H(hash_klass, n, *a)
29
+ nlen = 2 * ((('%x' % [n]).length * 4 + 7) >> 3)
30
+
31
+ hashin = a.map do |s|
32
+ next unless s
33
+ shex = (s.class == String) ? s : num_to_hex(s)
34
+ if shex.length > nlen
35
+ raise 'Bit width does not match - client uses different prime'
36
+ end
37
+ '0' * (nlen - shex.length) + shex
38
+ end.join('')
39
+
40
+ sha_hex(hashin, hash_klass).hex % n
41
+ end
42
+
43
+ # Multiplier parameter
44
+ # k = H(N, g) (in SIRP-6a)
45
+ def calc_k(n, g, hash_klass)
46
+ H(hash_klass, n, n, g)
47
+ end
48
+
49
+ # Private key (derived from username, raw password and salt)
50
+ # x = H(salt || H(username || ':' || password))
51
+ def calc_x(username, password, salt, hash_klass)
52
+ spad = salt.length.odd? ? '0' : ''
53
+ sha_hex(spad + salt + sha_str([username, password].join(':'), hash_klass), hash_klass).hex
54
+ end
55
+
56
+ # Random scrambling parameter
57
+ # u = H(A, B)
58
+ def calc_u(xaa, xbb, n, hash_klass)
59
+ H(hash_klass, n, xaa, xbb)
60
+ end
61
+
62
+ # Password verifier
63
+ # v = g^x (mod N)
64
+ def calc_v(x, n, g)
65
+ mod_exp(g, x, n)
66
+ end
67
+
68
+ # A = g^a (mod N)
69
+ def calc_A(a, n, g)
70
+ mod_exp(g, a, n)
71
+ end
72
+
73
+ # B = g^b + k v (mod N)
74
+ def calc_B(b, k, v, n, g)
75
+ (mod_exp(g, b, n) + k * v) % n
76
+ end
77
+
78
+ # Client secret
79
+ # S = (B - (k * g^x)) ^ (a + (u * x)) % N
80
+ def calc_client_S(bb, a, k, x, u, n, g)
81
+ mod_exp((bb - k * mod_exp(g, x, n)) % n, (a + x * u), n)
82
+ end
83
+
84
+ # Server secret
85
+ # S = (A * v^u) ^ b % N
86
+ def calc_server_S(aa, b, v, u, n)
87
+ mod_exp((mod_exp(v, u, n) * aa), b, n)
88
+ end
89
+
90
+ # M = H(A, B, K)
91
+ def calc_M(xaa, xbb, xkk, hash_klass)
92
+ digester = hash_klass.new
93
+ digester << hex_to_bytes(xaa).pack('C*')
94
+ digester << hex_to_bytes(xbb).pack('C*')
95
+ digester << hex_to_bytes(xkk).pack('C*')
96
+ digester.hexdigest
97
+ end
98
+
99
+ # H(A, M, K)
100
+ def calc_H_AMK(xaa, xmm, xkk, hash_klass)
101
+ byte_string = hex_to_bytes([xaa, xmm, xkk].join('')).pack('C*')
102
+ sha_str(byte_string, hash_klass).hex
103
+ end
104
+
105
+ def num_to_hex(num)
106
+ hex_str = num.to_s(16)
107
+ even_hex_str = hex_str.length.odd? ? '0' + hex_str : hex_str
108
+ even_hex_str.downcase
109
+ end
110
+
111
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
112
+ def Ng(group)
113
+ case group
114
+ when 1024
115
+ @N = %w(
116
+ EEAF0AB9 ADB38DD6 9C33F80A FA8FC5E8 60726187 75FF3C0B 9EA2314C
117
+ 9C256576 D674DF74 96EA81D3 383B4813 D692C6E0 E0D5D8E2 50B98BE4
118
+ 8E495C1D 6089DAD1 5DC7D7B4 6154D6B6 CE8EF4AD 69B15D49 82559B29
119
+ 7BCF1885 C529F566 660E57EC 68EDBC3C 05726CC0 2FD4CBF4 976EAA9A
120
+ FD5138FE 8376435B 9FC61D2F C0EB06E3
121
+ ).join.hex
122
+ @g = 2
123
+ @hash = Digest::SHA1
124
+
125
+ when 1536
126
+ @N = %w(
127
+ 9DEF3CAF B939277A B1F12A86 17A47BBB DBA51DF4 99AC4C80 BEEEA961
128
+ 4B19CC4D 5F4F5F55 6E27CBDE 51C6A94B E4607A29 1558903B A0D0F843
129
+ 80B655BB 9A22E8DC DF028A7C EC67F0D0 8134B1C8 B9798914 9B609E0B
130
+ E3BAB63D 47548381 DBC5B1FC 764E3F4B 53DD9DA1 158BFD3E 2B9C8CF5
131
+ 6EDF0195 39349627 DB2FD53D 24B7C486 65772E43 7D6C7F8C E442734A
132
+ F7CCB7AE 837C264A E3A9BEB8 7F8A2FE9 B8B5292E 5A021FFF 5E91479E
133
+ 8CE7A28C 2442C6F3 15180F93 499A234D CF76E3FE D135F9BB
134
+ ).join.hex
135
+ @g = 2
136
+ @hash = Digest::SHA1
137
+
138
+ when 2048
139
+ @N = %w(
140
+ AC6BDB41 324A9A9B F166DE5E 1389582F AF72B665 1987EE07 FC319294
141
+ 3DB56050 A37329CB B4A099ED 8193E075 7767A13D D52312AB 4B03310D
142
+ CD7F48A9 DA04FD50 E8083969 EDB767B0 CF609517 9A163AB3 661A05FB
143
+ D5FAAAE8 2918A996 2F0B93B8 55F97993 EC975EEA A80D740A DBF4FF74
144
+ 7359D041 D5C33EA7 1D281E44 6B14773B CA97B43A 23FB8016 76BD207A
145
+ 436C6481 F1D2B907 8717461A 5B9D32E6 88F87748 544523B5 24B0D57D
146
+ 5EA77A27 75D2ECFA 032CFBDB F52FB378 61602790 04E57AE6 AF874E73
147
+ 03CE5329 9CCC041C 7BC308D8 2A5698F3 A8D0C382 71AE35F8 E9DBFBB6
148
+ 94B5C803 D89F7AE4 35DE236D 525F5475 9B65E372 FCD68EF2 0FA7111F
149
+ 9E4AFF73
150
+ ).join.hex
151
+ @g = 2
152
+ @hash = Digest::SHA256
153
+
154
+ when 3072
155
+ @N = %w(
156
+ FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
157
+ 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
158
+ 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
159
+ A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
160
+ 49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
161
+ FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
162
+ 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
163
+ 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
164
+ 3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
165
+ 04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
166
+ B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
167
+ 1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
168
+ BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
169
+ E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
170
+ ).join.hex
171
+ @g = 5
172
+ @hash = Digest::SHA256
173
+
174
+ when 4096
175
+ @N = %w(
176
+ FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
177
+ 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
178
+ 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
179
+ A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
180
+ 49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
181
+ FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
182
+ 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
183
+ 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
184
+ 3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
185
+ 04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
186
+ B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
187
+ 1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
188
+ BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
189
+ E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26
190
+ 99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB
191
+ 04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2
192
+ 233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127
193
+ D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199
194
+ FFFFFFFF FFFFFFFF
195
+ ).join.hex
196
+ @g = 5
197
+ @hash = Digest::SHA256
198
+
199
+ when 6144
200
+ @N = %w(
201
+ FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
202
+ 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
203
+ 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
204
+ A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
205
+ 49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
206
+ FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
207
+ 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
208
+ 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
209
+ 3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
210
+ 04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
211
+ B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
212
+ 1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
213
+ BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
214
+ E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26
215
+ 99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB
216
+ 04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2
217
+ 233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127
218
+ D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492
219
+ 36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406
220
+ AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918
221
+ DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151
222
+ 2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03
223
+ F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F
224
+ BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA
225
+ CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B
226
+ B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632
227
+ 387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E
228
+ 6DCC4024 FFFFFFFF FFFFFFFF
229
+ ).join.hex
230
+ @g = 5
231
+ @hash = Digest::SHA256
232
+
233
+ when 8192
234
+ @N = %w(
235
+ FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
236
+ 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
237
+ 302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
238
+ A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
239
+ 49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
240
+ FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
241
+ 670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
242
+ 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
243
+ 3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
244
+ 04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
245
+ B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
246
+ 1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
247
+ BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
248
+ E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26
249
+ 99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB
250
+ 04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2
251
+ 233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127
252
+ D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492
253
+ 36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406
254
+ AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918
255
+ DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151
256
+ 2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03
257
+ F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F
258
+ BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA
259
+ CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B
260
+ B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632
261
+ 387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E
262
+ 6DBE1159 74A3926F 12FEE5E4 38777CB6 A932DF8C D8BEC4D0 73B931BA
263
+ 3BC832B6 8D9DD300 741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C
264
+ 5AE4F568 3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9
265
+ 22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B 4BCBC886
266
+ 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A 062B3CF5 B3A278A6
267
+ 6D2A13F8 3F44F82D DF310EE0 74AB6A36 4597E899 A0255DC1 64F31CC5
268
+ 0846851D F9AB4819 5DED7EA1 B1D510BD 7EE74D73 FAF36BC3 1ECFA268
269
+ 359046F4 EB879F92 4009438B 481C6CD7 889A002E D5EE382B C9190DA6
270
+ FC026E47 9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71
271
+ 60C980DD 98EDD3DF FFFFFFFF FFFFFFFF
272
+ ).join.hex
273
+ @g = 19
274
+ @hash = Digest::SHA256
275
+ else
276
+ raise NotImplementedError, 'unknown group size'
277
+ end
278
+
279
+ [@N, @g, @hash]
280
+ end
281
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
282
+ end
283
+ end