Class: SecretSharing::Shamir::Secret
- Inherits:
-
Object
- Object
- SecretSharing::Shamir::Secret
- Includes:
- SecretSharing::Shamir
- Defined in:
- lib/secretsharing/shamir/secret.rb
Overview
A SecretSharing::Shamir::Secret object represents a Secret in the Shamir secret sharing scheme. Secrets can be passed in as an input argument when creating a new SecretSharing::Shamir::Container or can be the output from a Container that has successfully decoded shares. A new Secret take 0 or 1 args. Zero args means the Secret will be initialized with a random Numeric object with the Secret::DEFAULT_BITLENGTH. If a single argument is passed it can be a String, or Integer. If its a String, its expected to be of a special encoding that was generated as the output of calling #to_s on another Secret object. If the object type is an Integer it can be up to 4096 bits in length.
All secrets are internally represented as a Numeric which can be retrieved in its raw form using #secret.
Constant Summary collapse
- MAX_BITLENGTH =
FIXME : Is a MAX_BITLENGTH really needed? Can it be larger if so?
4096
Instance Attribute Summary collapse
-
#bitlength ⇒ Object
Returns the value of attribute bitlength.
-
#hmac ⇒ Object
Returns the value of attribute hmac.
-
#secret ⇒ Object
Returns the value of attribute secret.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Secrets are equal if the Numeric in @secret is the same.
-
#initialize(opts = {}) ⇒ Secret
constructor
rubocop:disable Metrics/PerceivedComplexity.
- #secret? ⇒ Boolean
- #to_s ⇒ Object
-
#valid_hmac? ⇒ Boolean
See : generate_hmac.
Methods included from SecretSharing::Shamir
#evaluate_polynomial_at, #extended_gcd, #get_prime_number, #get_random_number, #get_random_number_with_bitlength, #invmod, #lagrange, #miller_rabin_prime?, #mod_exp
Constructor Details
#initialize(opts = {}) ⇒ Secret
rubocop:disable Metrics/PerceivedComplexity
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 |
# File 'lib/secretsharing/shamir/secret.rb', line 46 def initialize(opts = {}) opts = { :secret => get_random_number(32) # 32 Bytes, 256 Bits }.merge!(opts) # override with options opts.each_key do |k| if self.respond_to?("#{k}=") send("#{k}=", opts[k]) else fail ArgumentError, "Argument '#{k}' is not allowed" end end # FIXME : Do we really need the ability for a String arg to re-instantiate a Secret? # FIXME : If its a String, shouldn't it be able to be an arbitrary String converted to/from a Number? if opts[:secret].is_a?(String) # Decode a Base64.urlsafe_encode64 String which contains a Base 36 encoded Bignum back into a Bignum # See : Secret#to_s for forward encoding method. stripped_secret = opts[:secret].strip fail ArgumentError, 'invalid secret (empty String)' if stripped_secret.empty? decoded_secret = Base64.urlsafe_decode64(stripped_secret) fail ArgumentError, 'invalid secret (base64 decode returned nil or empty String)' if decoded_secret.empty? int_secret = decoded_secret.to_i(36) fail ArgumentError, 'invalid secret (not an Integer)' unless int_secret.is_a?(Integer) fail ArgumentError, 'invalid secret (Integer bit length < 100)' unless int_secret.bit_length > 100 @secret = int_secret end @secret = opts[:secret] if @secret.nil? fail ArgumentError, "Secret must be an Integer, not a '#{@secret.class}'" unless @secret.is_a?(Integer) # Get the number of binary bits in this secret's value. @bitlength = @secret.bit_length fail ArgumentError, "Secret must have a bitlength less than or equal to #{MAX_BITLENGTH}" if @bitlength > MAX_BITLENGTH generate_hmac end |
Instance Attribute Details
#bitlength ⇒ Object
Returns the value of attribute bitlength.
40 41 42 |
# File 'lib/secretsharing/shamir/secret.rb', line 40 def bitlength @bitlength end |
#hmac ⇒ Object
Returns the value of attribute hmac.
40 41 42 |
# File 'lib/secretsharing/shamir/secret.rb', line 40 def hmac @hmac end |
#secret ⇒ Object
Returns the value of attribute secret.
41 42 43 |
# File 'lib/secretsharing/shamir/secret.rb', line 41 def secret @secret end |
Instance Method Details
#==(other) ⇒ Object
Secrets are equal if the Numeric in @secret is the same. Do secure constant-time comparison of the objects.
90 91 92 93 94 |
# File 'lib/secretsharing/shamir/secret.rb', line 90 def ==(other) other_secret_hash = RbNaCl::Hash.blake2b(other.secret.to_s, digest_size: 32) own_secret_hash = RbNaCl::Hash.blake2b(@secret.to_s, digest_size: 32) RbNaCl::Util.verify32(other_secret_hash, own_secret_hash) end |
#secret? ⇒ Boolean
102 103 104 |
# File 'lib/secretsharing/shamir/secret.rb', line 102 def secret? @secret.is_a?(Integer) end |
#to_s ⇒ Object
106 107 108 109 110 111 |
# File 'lib/secretsharing/shamir/secret.rb', line 106 def to_s # Convert the Bignum to a Base 36 encoded String # Wrap the Base 36 encoded String as a URL safe Base 64 encoded String # Combined this should result in a relatively compact and portable String Base64.urlsafe_encode64(@secret.to_s(36)) end |
#valid_hmac? ⇒ Boolean
See : generate_hmac
114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/secretsharing/shamir/secret.rb', line 114 def valid_hmac? return false if !@secret.is_a?(Integer) || @hmac.to_s.empty? || @secret.to_s.empty? hash = RbNaCl::Hash.sha512(@secret.to_s) key = hash[0, 32] authenticator = RbNaCl::Util.hex2bin(@hmac) msg = hash[33, 64] begin RbNaCl::HMAC::SHA256.verify(key, authenticator, msg) rescue false end end |