Skip to content

Commit

Permalink
document key pair generation (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
jshawl authored Feb 7, 2024
1 parent 511413f commit 8f9b5b4
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 12 deletions.
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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

```
Expand Down
14 changes: 10 additions & 4 deletions lib/minisign/key_pair.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand All @@ -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*')
Expand All @@ -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
Expand All @@ -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

# 🤷
Expand Down
2 changes: 2 additions & 0 deletions lib/minisign/private_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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*')
Expand Down

0 comments on commit 8f9b5b4

Please sign in to comment.