Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0.2)
cmake_minimum_required(VERSION 3.8.0)
project(pgp-test)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
Expand Down Expand Up @@ -40,3 +40,5 @@ if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.2)
set_property(TARGET generate_derived_key PROPERTY CXX_STANDARD 20)
add_compile_options(-fconcepts -DHAVE_CPP20_CONCEPTS)
endif()

add_subdirectory(tests)
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
PGP key generation
==================
# PGP key generation

This repository provides the source for a utility used for creating
PGP keys using libsodium. The keys generated can be deterministic.

DEPENDENCIES
============
## Dependencies

This repository depends only on the pgp-packet-library - and the
dependencies it has.
The source code can be built using only the dependencies of the
pgp-packet-library. The integration testing script, which can be run using
`make test` in the build folder, additionally requires Python 3.7 (or 3.6 with
the `dataclasses` library) and GnuPG to be installed.

GENERATING NEW KEYS
===============
## Generating new keys

- If you have a new smartcard, change the user and admin pin first. See: https://www.gnupg.org/howtos/card-howto/en/ch03s02.html

Expand Down Expand Up @@ -54,7 +53,6 @@ You should now have a functional key. You can test it as follows:
- gpg -r [key id] --encrypt test.txt
- gpg --decrypt test.txt.gpg

UPDATING EXISTING KEYS
===============
## Updating existing keys

If you want to change the expiry date of existing keys, you can simply follow the steps above again to generate a new key with a different expiry date, using your encrypted seed and passphrase.
7 changes: 4 additions & 3 deletions generate_derived_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,12 @@ namespace {
Options options;

// description of the options for the boost option parser
po::options_description optdesc;
// Set the line length to 100 for slightly wider option descriptions
po::options_description optdesc(100);
optdesc.add_options()
("help,h", "Produce help message")
("output-file,o", po::value<opt_prompt<std::string>>(&options.output_file), "Output file")
("key-type,t", po::value<opt_prompt<key_class>> (&options.type), "Type of the generated key (eddsa/ecdsa)")
("key-type,t", po::value<opt_prompt<key_class>> (&options.type), "Type of the generated key (eddsa/ecdsa/rsa{2048,4096,8192})")
("name,n", po::value<opt_prompt<std::string>>(&options.user_name), "Your name (firstname lastname)")
("email,e", po::value<opt_prompt<std::string>>(&options.user_email), "Your email address")
("sigtime,s", po::value<opt_prompt<tm_wrapper>> (&options.signature_creation), "Signature creation time in UTC (YYYY-MM-DD HH:MM:SS)")
Expand Down Expand Up @@ -286,7 +287,7 @@ namespace {

// ensure that all the options are initialized by possibly reading some from standard input
options.output_file .ensure_prompt("Output file");
options.type .ensure_prompt("Type of the generated key (eddsa/ecdsa)");
options.type .ensure_prompt("Type of the generated key (eddsa/ecdsa/rsa{2048,4096,8192})");
options.user_name .ensure_prompt("Your name (firstname lastname)");
options.user_email .ensure_prompt("Your email address");
options.signature_creation .ensure_prompt("Signature creation time in UTC (YYYY-MM-DD HH:MM:SS)");
Expand Down
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
5 changes: 5 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_custom_target(integration-test
COMMAND ${CMAKE_CURRENT_LIST_DIR}/integration_test.py ${CMAKE_BINARY_DIR}/generate_derived_key)

add_custom_target(test
DEPENDS generate_derived_key integration-test)
22 changes: 22 additions & 0 deletions tests/date_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import datetime


def is_leap_year(year):
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

def days_in_month(year, month):
if month == 2:
if is_leap_year(year): return 29
else: return 28
return [31, None, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1]

# Convert a string date representation to a UNIX timestamp
def date_to_unix(string):
return int(
# parse the string into a datetime object
datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
# tell it to consider itself a UTC time
.replace(tzinfo = datetime.timezone.utc)
# obtain the timestamp
.timestamp()
)
67 changes: 67 additions & 0 deletions tests/generate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import random

from date_utils import *


# Class hierarchy for randomly generating various kinds of data for input into
# the program
class Generate:
def generate():
raise NotImplementedError()

class GenerateString(Generate):
def generate():
length = random.randint(1, 200)
return "".join([chr(random.randint(ord(' '), ord('~'))) for _ in range(length)])

class GenerateName(GenerateString):
pass

class GenerateEmail(GenerateString):
pass

class GenerateDate(Generate):
def generate():
while True:
year = random.randint(1990, 2100)
month = random.randint(1, 12)
day = random.randint(1, days_in_month(year, month))
hour = random.randint(0, 23)
minute = random.randint(0, 59)
second = random.randint(0, 59)
string = "{:04}-{:02}-{:02} {:02}:{:02}:{:02}".format(year, month, day, hour, minute, second)
if date_to_unix(string) >= 1511740800: # TODO: Change to variable date
return string

class GenerateDatePair(Generate):
def generate():
while True:
values = [GenerateDate.generate(), GenerateDate.generate()]
# if values[0] == values[1]:
# continue
values.sort()
return tuple(values)

class GenerateDie(Generate):
def generate():
return random.randint(1, 6)

class GenerateDice(Generate):
def generate():
length = 100 if random.randint(0, 1) == 0 else random.randint(100, 1000)
return "".join(str(GenerateDie.generate()) for _ in range(length))

class GenerateSymmetricKey(GenerateString):
pass

class GenerateInput():
def generate():
datepair = GenerateDatePair.generate()
return {
"name": GenerateName.generate(),
"email": GenerateEmail.generate(),
"creation": datepair[0],
"expiration": datepair[1],
"dice": GenerateDice.generate(),
"key": GenerateSymmetricKey.generate(),
}
Loading