class KeyTool
Public Class Methods
new()
click to toggle source
# File lib/universa/keytool/keytool.rb, line 43 def initialize @require_password = true @autogenerate_password = false @tasks = [] @rounds = 1000000 init_parser() end
Public Instance Methods
check_overwrite(output)
click to toggle source
# File lib/universa/keytool/keytool.rb, line 103 def check_overwrite output error "File #{output} already exists" if File.exists?(output) && !@overwrite end
init_parser()
click to toggle source
# File lib/universa/keytool/keytool.rb, line 119 def init_parser opt_parser = OptionParser.new { |opts| opts.banner = ANSI.bold { "\nUniversa Key tool #{Universa::VERSION}" } opts.separator "" opts.on("--no-password", "create resources not protected by password. Not recommended.") { |x| @require_password = x } opts.on("-a", "--autogenerate_password", "the new secure password will be generated and shown on the console", "while the password is safe, printing it out to the console may not.", "Normally, system promts the password on the console that is", "more secure") { |x| @autogenerate_password = x } opts.on("-o FILE", "--output FILE", "file name for the output file") { |f| @output_file = f } opts.on("-F", "--force", "force overwrite file") { @overwrite = true } opts.on("-g SIZE", "--generate SIZE", "generate new private key of the specified bis size") { |s| task { strength = s.to_i case strength when 2048, 4096 task { # check we have all to generate... output = output_file(".private.unikey") check_overwrite(output) key = PrivateKey.new(strength) save_key(output, key) puts "\nNew private key is generated: #{output}" } else error "Only supported key sizes are 2048, 4096" end } } opts.on("-u FILE", "--update FILE", "update password on the existing key (also add/remove", "requires -o output_file or --overwrite to change it in place") { |name| task { output = output_file(".private.unikey", name) check_overwrite output key = load_key(name) puts("\rKey loaded OK ") save_key output, key } } opts.on("-r ROUNDS", "--rounds ROUNDS", "how many PBKDF2 rounds to use when saving with password", "(1 million by default, the more the better, but takes time)") { |r| @rounds = human_to_i(r) @rounds < 100000 and error "To few rounds, use at least 100000" } opts.on("-s FILE", "--show FILE", "show key information") { |name| task { key = load_key(name) puts "\r----------------------------------------------------------------------------------------" puts "Private key, #{key.info.getKeyLength() * 8} bits\n" puts "Short address : #{ANSI.bold { key.short_address.to_s }}" puts "Long address : #{ANSI.bold { key.long_address.to_s }}" } } opts.separator "" def sample(text) " " + ANSI.bold { ANSI.green { text } } end opts.on_tail("-h", "--help", "Show this message") do puts opts puts <<-End #{ANSI.bold { "Usage samples:" }} Generate new key 'foo.private.unikey' - will ask password from console (notice extension will be added automatically) #{sample "unikeys -g 2048 -o foo"} Show foo addresses: #{sample "unikeys -s foo.private.unikey"} Change password of the foo key and save it into new file bar.private.unikey (keeping both for security), will ask new password from console #{sample "unikeys -u foo.private.unikey -o bar"} Change password in place (overwriting old file) #{sample "unikeys -u foo.private.unikey -f"} See project home page at #{ANSI.underline { "https://github.com/sergeych/universa" }} End exit end opts.on_tail("-v", "--version", "Show versions") do puts "Universa core version: #{Service.umi.core_version}" puts "UMI version : #{Service.umi.version}" client = Universa::Client.new puts "Connected nodes : #{client.size}" exit end } begin opt_parser.order! if @tasks.empty? puts "nothing to do. Please specify one of: -g, -s or -u. See help for more (-h)." else @tasks.each { |t| t.call } end rescue MessageException, OptionParser::ParseError => e STDERR.puts ANSI.red { ANSI.bold { "\nError: #{e}\n" } } exit(1000) rescue Interrupt exit(1010) rescue STDERR.puts ANSI.red { "\n#{$!.backtrace.reverse.join("\n")}\n" } STDERR.puts ANSI.red { ANSI.bold { "Error: #$! (#{$!.class.name})" } } exit(2000) end end
load_key(name)
click to toggle source
# File lib/universa/keytool/keytool.rb, line 83 def load_key(name) packed = open(name, 'rb') { |f| f.read } rescue error("can't read file: #{name}") begin PrivateKey.from_packed(packed) rescue Exception => e if e.message.include?('PasswordProtectedException') puts "\nThe key is password-protected" while (true) puts "\renter password for #{name}:" password = STDIN.noecho(&:gets).chomp STDOUT << ANSI.faint { "trying to decrypt..." } key = PrivateKey.from_packed(packed, password: password) rescue nil key and break key end else error "can't load the key (file corrupt?)" end end end
output_file(extension = nil, overwrite_existing_name = nil)
click to toggle source
# File lib/universa/keytool/keytool.rb, line 74 def output_file(extension = nil, overwrite_existing_name = nil) name = @output_file if !name (overwrite_existing_name && @overwrite) or error "specify output file with -o / --output" name = overwrite_existing_name end extension && !name.end_with?(extension) ? "#{name}#{extension}" : name end
sample(text)
click to toggle source
# File lib/universa/keytool/keytool.rb, line 193 def sample(text) " " + ANSI.bold { ANSI.green { text } } end
save_key(name, key)
click to toggle source
# File lib/universa/keytool/keytool.rb, line 107 def save_key name, key open(name, 'wb') { |f| f << if @require_password password = session_password puts "\nEncrypting key with #@rounds PBKDF rounds..." key.pack_with_password(password, @rounds) else key.pack() end } end
session_password()
click to toggle source
# File lib/universa/keytool/keytool.rb, line 55 def session_password @require_password or return nil @session_password ||= begin if @autogenerate_password psw = 29.random_alnums puts "Autogenerated password: #{ANSI.bold { psw }}" psw else puts "\nPlease enter password for key to be generated" psw1 = STDIN.noecho(&:gets).chomp puts "Please re-enter the password" psw2 = STDIN.noecho(&:gets).chomp psw1 == psw2 or error "passwords do not match" psw1.length < 8 and error "password is too short" psw1 end end end
task(&block)
click to toggle source
# File lib/universa/keytool/keytool.rb, line 51 def task &block @tasks << block end