diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..1ad899d Binary files /dev/null and b/.DS_Store differ diff --git a/lib/minisign/private_key.rb b/lib/minisign/private_key.rb index 5037a57..99099ba 100644 --- a/lib/minisign/private_key.rb +++ b/lib/minisign/private_key.rb @@ -5,7 +5,7 @@ module Minisign class PrivateKey include Utils attr_reader :signature_algorithm, :kdf_algorithm, :cksum_algorithm, :kdf_salt, :kdf_opslimit, :kdf_memlimit, - :key_id, :public_key, :secret_key, :checksum + :key_id, :ed25519_public_key, :secret_key, :checksum # rubocop:disable Metrics/AbcSize # rubocop:disable Layout/LineLength @@ -35,7 +35,7 @@ def initialize(str, password = nil) else bytes[54..157] end - @key_id, @secret_key, @public_key, @checksum = key_data(@key_data_bytes) + @key_id, @secret_key, @ed25519_public_key, @checksum = key_data(@key_data_bytes) assert_keypair_match! end # rubocop:enable Layout/LineLength @@ -44,7 +44,7 @@ def initialize(str, password = nil) # @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 + raise 'Wrong password for that key' if @ed25519_public_key != ed25519_signing_key.verify_key.to_bytes.bytes end def key_data(bytes) @@ -56,6 +56,11 @@ def ed25519_signing_key Ed25519::SigningKey.new(@secret_key.pack('C*')) end + def public_key + data = Base64.strict_encode64("Ed#{@key_id.pack('C*')}#{ed25519_signing_key.verify_key.to_bytes}") + Minisign::PublicKey.new(data) + end + # Sign a file/message # # @param filename [String] The filename to be used in the trusted comment section diff --git a/lib/minisign/public_key.rb b/lib/minisign/public_key.rb index 0a0c852..37f3523 100644 --- a/lib/minisign/public_key.rb +++ b/lib/minisign/public_key.rb @@ -15,7 +15,7 @@ def initialize(str) @public_key = @decoded[10..] @verify_key = Ed25519::VerifyKey.new(@public_key) @untrusted_comment = if parts.length == 1 - "minisign public key #{key_id}\n#{key_data}\n" + "minisign public key #{key_id}" else parts.first.split('untrusted comment: ').last end diff --git a/spec/minisign/key_pair_spec.rb b/spec/minisign/key_pair_spec.rb index 8ee4e8f..c12be5e 100644 --- a/spec/minisign/key_pair_spec.rb +++ b/spec/minisign/key_pair_spec.rb @@ -5,18 +5,26 @@ keypair = Minisign::KeyPair.new expect(keypair.private_key).to be_truthy File.write('test/generated/new-unencrypted-keypair.key', keypair.private_key) + File.write('test/generated/new-unencrypted-keypair.pub', keypair.public_key) expect(system( 'test/generated/minisign -Sm test/generated/.keep -s test/generated/new-unencrypted-keypair.key' )).to be(true) + expect(system( + 'test/generated/minisign -Vm test/generated/.keep -p test/generated/new-unencrypted-keypair.pub' + )).to be(true) end it 'generates a keypair with a password' do keypair = Minisign::KeyPair.new('secret password') expect(keypair.private_key).to be_truthy File.write('test/generated/new-encrypted-keypair.key', keypair.private_key) + File.write('test/generated/new-encrypted-keypair.pub', keypair.public_key) expect(system( # rubocop:disable Layout/LineLength "echo 'secret password' | test/generated/minisign -Sm test/generated/.keep -s test/generated/new-encrypted-keypair.key" # rubocop:enable Layout/LineLength )).to be(true) + expect(system( + 'test/generated/minisign -Vm test/generated/.keep -p test/generated/new-encrypted-keypair.pub' + )).to be(true) end end diff --git a/spec/minisign/private_key_spec.rb b/spec/minisign/private_key_spec.rb index 916e3b9..d689960 100644 --- a/spec/minisign/private_key_spec.rb +++ b/spec/minisign/private_key_spec.rb @@ -53,8 +53,9 @@ end it 'parses the public key' do - expect(@private_key.public_key).to eq([108, 35, 192, 26, 47, 128, 233, 165, 133, 38, 242, 5, 76, 55, 135, 40, - 103, 72, 230, 43, 184, 117, 219, 37, 173, 250, 196, 122, 252, 174, 173, 140]) # rubocop:disable Layout/LineLength + key = @private_key.ed25519_public_key + expect(key).to eq([108, 35, 192, 26, 47, 128, 233, 165, 133, 38, 242, 5, 76, 55, 135, 40, + 103, 72, 230, 43, 184, 117, 219, 37, 173, 250, 196, 122, 252, 174, 173, 140]) end it 'parses the secret key' do @@ -70,7 +71,7 @@ [69, 100], @private_key.key_id, @private_key.secret_key, - @private_key.public_key + @private_key.ed25519_public_key ].inject(&:+).pack('C*') computed_checksum = blake2b256(key_data).bytes @@ -80,6 +81,12 @@ it 'can be written to a file' do expect(@private_key.to_s).to eq(File.read('test/minisign.key')) end + + it 'can recreate the public key from the private key' do + # remove the custom untrusted comment + original = File.read('test/minisign.pub').gsub(' yay', '') + expect(@private_key.public_key.to_s).to eq(original) + end end describe 'sign' do