From 8f9b5b4c6f9db792ebd36f4aa50c5b397aaef659 Mon Sep 17 00:00:00 2001 From: Jesse Shawl Date: Wed, 7 Feb 2024 17:41:17 -0600 Subject: [PATCH] document key pair generation (#16) --- README.md | 23 +++++++++++++++-------- lib/minisign/key_pair.rb | 14 ++++++++++---- lib/minisign/private_key.rb | 2 ++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 484c82f..4ab59d3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ A rubygem for creating and verifying [Minisign](http://jedisct1.github.io/minisi - [Installation \& Usage](#installation--usage) - [Read a public key](#read-a-public-key) - [Verify a signature](#verify-a-signature) + - [Read a private key](#read-a-private-key) - [Create a signature](#create-a-signature) + - [Generate a key pair](#generate-a-key-pair) - [Local Development](#local-development) - [Documentation](#documentation) @@ -27,31 +29,36 @@ public_key = Minisign::PublicKey.new(File.read("test/minisign.pub")) ### Verify a signature ```rb -require 'minisign' -public_key = Minisign::PublicKey.new('RWSmKaOrT6m3TGwjwBovgOmlhSbyBUw3hyhnSOYruHXbJa36xHr8rq2M') message = File.read("test/example.txt") signature = Minisign::Signature.new(File.read("test/example.txt.minisig")) public_key.verify(signature, message) ``` -The above is equivalent to: +### Read a private key -``` -minisign -Vm test/example.txt -P RWSmKaOrT6m3TGwjwBovgOmlhSbyBUw3hyhnSOYruHXbJa36xHr8rq2M +```rb +password = "password" # optional, if the key is not encrypted +private_key = Minisign::PrivateKey.new(File.read("minisign.key"), password) ``` ### Create a signature ```rb -require 'minisign' file_path = "example.txt" password = "password" -private_key = Minisign::PrivateKey.new(File.read("minisign.key"), password) signature = private_key.sign(file_path, File.read(file_path)) - File.write("#{file_path}.minisig", signature.to_s) ``` +### Generate a key pair + +```rb +password = "password" # or nil, to generate a private key without encryption +keypair = Minisign::KeyPair.new(password) +keypair.private_key # Minisign::PrivateKey +keypair.public_key # Minisign::PublicKey +``` + ## Local Development ``` diff --git a/lib/minisign/key_pair.rb b/lib/minisign/key_pair.rb index a9a8b6e..3709ee8 100644 --- a/lib/minisign/key_pair.rb +++ b/lib/minisign/key_pair.rb @@ -7,7 +7,8 @@ class KeyPair def initialize(password = nil) @password = password - + @key_id = SecureRandom.bytes(8) + @signing_key = Ed25519::SigningKey.generate kd = key_data @checksum = blake2b256("Ed#{kd}") @@ -18,6 +19,7 @@ def initialize(password = nil) @kdf_algorithm = password.nil? ? [0, 0].pack('U*') : 'Sc' end + # @return [Minisign::PrivateKey] def private_key @kdf_opslimit = kdf_opslimit_bytes.pack('C*') @kdf_memlimit = kdf_memlimit_bytes.pack('C*') @@ -28,6 +30,12 @@ def private_key ) end + # @return [Minisign::PublicKey] + def public_key + data = Base64.strict_encode64("Ed#{@key_id}#{@signing_key.verify_key.to_bytes}") + Minisign::PublicKey.new(data) + end + private def kdf_output @@ -40,9 +48,7 @@ def kdf_output end def key_data - key_id = SecureRandom.bytes(8) - signing_key = Ed25519::SigningKey.generate - "#{key_id}#{signing_key.to_bytes}#{signing_key.verify_key.to_bytes}" + "#{@key_id}#{@signing_key.to_bytes}#{@signing_key.verify_key.to_bytes}" end # 🤷 diff --git a/lib/minisign/private_key.rb b/lib/minisign/private_key.rb index cf4067a..5037a57 100644 --- a/lib/minisign/private_key.rb +++ b/lib/minisign/private_key.rb @@ -42,6 +42,7 @@ def initialize(str, password = nil) # rubocop:enable Metrics/AbcSize # rubocop:enable Metrics/MethodLength + # @raise [RuntimeError] if the extracted public key does not match the derived public key def assert_keypair_match! raise 'Wrong password for that key' if @public_key != ed25519_signing_key.verify_key.to_bytes.bytes end @@ -74,6 +75,7 @@ def sign(filename, message, comment = nil) ].join("\n")) end + # @return [String] A string in the minisign.pub format def to_s kdf_salt = @kdf_salt.pack('C*') kdf_opslimit = [@kdf_opslimit, 0].pack('L*')