mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-26 12:58:02 +01:00
Add more documentation
This commit is contained in:
parent
50d31eb463
commit
df7505eadb
7 changed files with 213 additions and 22 deletions
|
@ -24,3 +24,4 @@ Contents
|
|||
quickstart.md
|
||||
pgpainless-cli/usage.md
|
||||
sop.md
|
||||
pgpainless-core/indepth.rst
|
1
docs/source/pgpainless-core/edit_keys.md
Normal file
1
docs/source/pgpainless-core/edit_keys.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Edit Keys
|
101
docs/source/pgpainless-core/generate_keys.md
Normal file
101
docs/source/pgpainless-core/generate_keys.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# PGPainless In-Depth: Generate Keys
|
||||
|
||||
There are two API endpoints for generating OpenPGP keys using `pgpainless-core`:
|
||||
|
||||
`PGPainless.generateKeyRing()` presents a selection of pre-configured OpenPGP key archetypes:
|
||||
|
||||
```java
|
||||
// Modern, EC-based OpenPGP key with dedicated primary certification key
|
||||
// This method is recommended by the authors
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing(
|
||||
"Alice <alice@pgpainless.org>",
|
||||
Passphrase.fromPassword("sw0rdf1sh"));
|
||||
|
||||
// Simple, EC-based OpenPGP key with combined certification and signing key
|
||||
// plus encryption subkey
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.simpleEcKeyRing(
|
||||
"Alice <alice@pgpainless.org>",
|
||||
Passphrase.fromPassword("0r4ng3"));
|
||||
|
||||
// Simple, RSA OpenPGP key made of a single RSA key used for all operations
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.simpleRsaKeyRing(
|
||||
"Alice <alice@pgpainless.org>",
|
||||
RsaLength._4096, Passphrase.fromPassword("m0nk3y")):
|
||||
```
|
||||
|
||||
If you have special requirements on algorithms you can use `PGPainless.buildKeyRing()` instead, which offers more
|
||||
control over parameters:
|
||||
|
||||
```java
|
||||
// Customized key
|
||||
|
||||
// Specification for primary key
|
||||
KeySpecBuilder primaryKeySpec = KeySpec.getBuilder(
|
||||
KeyType.RSA(RsaLength._8192), // 8192 bits RSA key
|
||||
KeyFlag.CERTIFY_OTHER) // used for certification
|
||||
// optionally override algorithm preferences
|
||||
.overridePreferredCompressionAlgorithms(CompressionAlgorithm.ZLIB)
|
||||
.overridePreferredHashAlgorithms(HashAlgorithm.SHA512, HashAlgorithm.SHA384)
|
||||
.overridePreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm.AES256);
|
||||
|
||||
// Specification for a signing subkey
|
||||
KeySpecBuilder signingSubKeySpec = KeySpec.getBuilder(
|
||||
KeyType.ECDSA(EllipticCurve._P256), // P-256 ECDSA key
|
||||
KeyFlag.SIGN_DATA); // Used for signing
|
||||
|
||||
// Specification for an encryption subkey
|
||||
KeySpecBuilder encryptionSubKeySpec = KeySpec.getBuilder(
|
||||
KeyType.ECDH(EllipticCurve._P256),
|
||||
KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE);
|
||||
|
||||
// Build the key itself
|
||||
PGPSecretKeyRing secretKey = PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(primaryKeySpec)
|
||||
.addSubkey(signingSubKeySpec)
|
||||
.addSubkey(encryptionSubKeySpec)
|
||||
.addUserId("Juliet <juliet@montague.lit>") // Primary User-ID
|
||||
.addUserId("xmpp:juliet@capulet.lit") // Additional User-ID
|
||||
.setPassphrase(Passphrase.fromPassword("romeo_oh_Romeo<3")) // passphrase protection
|
||||
.build();
|
||||
```
|
||||
|
||||
To specify, which algorithm to use for a single (sub) key, `KeySpec.getBuilder(_)` can be used, passing a `KeyType`,
|
||||
as well as some `KeyFlag`s as argument.
|
||||
|
||||
`KeyType` defines an algorithm and its parameters, e.g. RSA with a certain key size, or ECDH over a certain
|
||||
elliptic curve.
|
||||
Currently, PGPainless supports the following `KeyType`s:
|
||||
* `KeyType.RSA(_)`: Signing, Certification, Encryption
|
||||
* `KeyType.ECDH(_)`: Encryption
|
||||
* `KeyType.ECDSA(_)`: Signing, Certification
|
||||
* `KeyType.EDDSA(_)`: Signing, Certification
|
||||
* `KeyType.XDH(_)`: Encryption
|
||||
|
||||
The `KeyFlag`s are used to specify, how the key will be used later on. A signing key can only be used for signing,
|
||||
if it carries the `KeyFlag.SIGN_DATA`.
|
||||
A key can carry multiple key flags.
|
||||
|
||||
It is possible to override the default algorithm preferences used by PGPainless with custom preferences.
|
||||
An algorithm preference list contains algorithms from most to least preferred.
|
||||
|
||||
Every OpenPGP key MUST have a primary key. The primary key MUST be capable of certification, so you MUST use an
|
||||
algorithm that can be used to generate signatures.
|
||||
The primary key can be set by calling `setPrimaryKey(primaryKeySpec)`.
|
||||
|
||||
Furthermore, an OpenPGP key can contain zero or more subkeys.
|
||||
Those can be set by repeatedly calling `addSubkey(subkeySpec)`.
|
||||
|
||||
OpenPGP keys are usually bound to User-IDs like names and/or email addresses.
|
||||
There can be multiple user-ids bound to a key, in which case the very first User-ID will be marked as primary.
|
||||
To add a User-ID to the key, call `addUserId(userId)`.
|
||||
|
||||
By default, keys do not have an expiration date. This can be changed by setting an expiration date using
|
||||
`setExpirationDate(date)`.
|
||||
|
||||
To enable password protection for the OpenPGP key, you can call `setPassphrase(passphrase)`.
|
||||
If this method is not called, or if the passed in `Passphrase` is empty, the key will be unprotected.
|
||||
|
||||
Finally, calling `build()` will generate a fresh OpenPGP key according to the specifications given.
|
14
docs/source/pgpainless-core/indepth.rst
Normal file
14
docs/source/pgpainless-core/indepth.rst
Normal file
|
@ -0,0 +1,14 @@
|
|||
In-Depth Guide to pgpainless-core
|
||||
=================================
|
||||
|
||||
This is an in-depth introduction to OpenPGP using PGPainless.
|
||||
If you are looking for a quickstart introduction instead, check out [](quickstart.md).
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
generate_keys.md
|
||||
edit_keys.md
|
||||
userids.md
|
||||
passphrase.md
|
60
docs/source/pgpainless-core/passphrase.md
Normal file
60
docs/source/pgpainless-core/passphrase.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Passwords
|
||||
|
||||
In Java based applications, passing passwords as `String` objects has the
|
||||
[disadvantage](https://stackoverflow.com/a/8881376/11150851) that you have to rely on garbage collection to clean up
|
||||
once they are no longer used.
|
||||
For that reason, `char[]` is the preferred method for dealing with passwords.
|
||||
Once a password is no longer used, the character array can simply be overwritten to remove the sensitive data from
|
||||
memory.
|
||||
|
||||
## Passphrase
|
||||
PGPainless uses a wrapper class `Passphrase`, which takes care for the wiping of unused passwords:
|
||||
|
||||
```java
|
||||
Passphrase passphrase = new Passphrase(new char[] {'h', 'e', 'l', 'l', 'o'});
|
||||
assertTrue(passphrase.isValid());
|
||||
|
||||
assertArrayEquals(new char[] {'h', 'e', 'l', 'l', 'o'}, passphrase.getChars()):
|
||||
|
||||
// Once we are done, we can clean the data
|
||||
passphrase.clear();
|
||||
|
||||
assertFalse(passphrase.isValid());
|
||||
assertNull(passphrase.getChars());
|
||||
```
|
||||
|
||||
Furthermore, `Passphrase` can also wrap empty passphrases, which increases null-safety of the API:
|
||||
|
||||
```java
|
||||
Passphrase empty = Passphrase.emptyPassphrase();
|
||||
assertTrue(empty.isValid());
|
||||
assertTrue(empty.isEmpty());
|
||||
assertNull(empty.getChars());
|
||||
|
||||
empty.clear();
|
||||
|
||||
assertFalse(empty.isValid());
|
||||
```
|
||||
|
||||
## SecretKeyRingProtector
|
||||
|
||||
There are certain operations that require you to provide the passphrase for a key.
|
||||
Examples are decryption of messages, or creating signatures / certifications.
|
||||
|
||||
The primary way of telling PGPainless, which password to use for a certain key is the `SecretKeyRingProtector`
|
||||
interface.
|
||||
There are multiple implementations of this interface, which may or may not suite your needs:
|
||||
|
||||
```java
|
||||
// If your key is not password protected, this implementation is for you:
|
||||
SecretKeyRingProtector unprotected = SecretKeyRingProtector
|
||||
.unprotectedKeys();
|
||||
|
||||
// If you use a single passphrase for all (sub-) keys, take this:
|
||||
SecretKeyRingProtector singlePassphrase = SecretKeyRingProtector
|
||||
.unlockAnyKeyWith(passphrase);
|
||||
|
||||
// If you want to be flexible, use this:
|
||||
CachingSecretKeyRingProtector flexible = SecretKeyRingProtector
|
||||
.defaultSecretKeyRingProtector(passphraseCallback);
|
||||
```
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
The `pgpainless-core` module contains the bulk of the actual OpenPGP implementation.
|
||||
|
||||
This is a quickstart guide. For more in-depth exploration of the API, checkout [](indepth.md).
|
||||
|
||||
:::{note}
|
||||
This chapter is work in progress.
|
||||
:::
|
||||
|
@ -65,7 +67,7 @@ byte[] binary = secretKey.getEncoded();
|
|||
```
|
||||
|
||||
### Generate a Key
|
||||
PGPainless comes with a simple to use `KeyRingBuilder` class that helps you to quickly generate modern OpenPGP keys.
|
||||
PGPainless comes with a method to quickly generate modern OpenPGP keys.
|
||||
There are some predefined key archetypes, but it is possible to fully customize the key generation to fit your needs.
|
||||
|
||||
```java
|
||||
|
@ -78,27 +80,6 @@ PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
|||
.simpleRsaKeyRing("Juliet <juliet@montague.lit>", RsaLength._4096);
|
||||
```
|
||||
|
||||
To generate a customized key, use `PGPainless.buildKeyRing()` instead:
|
||||
|
||||
```java
|
||||
// Customized key
|
||||
PGPSecretKeyRing keyRing = PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(KeySpec.getBuilder(
|
||||
RSA.withLength(RsaLength._8192),
|
||||
KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)
|
||||
.overrideCompressionAlgorithms(CompressionAlgorithm.ZLIB)
|
||||
).addSubkey(
|
||||
KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256), KeyFlag.SIGN_DATA)
|
||||
).addSubkey(
|
||||
KeySpec.getBuilder(
|
||||
ECDH.fromCurve(EllipticCurve._P256),
|
||||
KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
|
||||
).addUserId("Juliet <juliet@montague.lit>")
|
||||
.addUserId("xmpp:juliet@capulet.lit")
|
||||
.setPassphrase(Passphrase.fromPassword("romeo_oh_Romeo<3"))
|
||||
.build();
|
||||
```
|
||||
|
||||
As you can see, it is possible to generate all kinds of different keys.
|
||||
|
||||
### Extract a Certificate
|
||||
|
|
33
docs/source/pgpainless-core/userids.md
Normal file
33
docs/source/pgpainless-core/userids.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# User-IDs
|
||||
|
||||
User-IDs are identities that users go by. A User-ID might be a name, an email address or both.
|
||||
User-IDs can also contain both and even have a comment.
|
||||
|
||||
In general, the format of a User-ID is not fixed, so it can contain arbitrary strings.
|
||||
However, it is agreed upon to use the
|
||||
Below is a selection of possible User-IDs:
|
||||
|
||||
```
|
||||
Firstname Lastname <email@address.tld> [Comment]
|
||||
Firstname Lastname
|
||||
Firstname Lastname [Comment]
|
||||
<email@address.tld>
|
||||
<email@address.tld> [Comment]
|
||||
```
|
||||
|
||||
PGPainless comes with a builder class `UserId`, which can be used to safely construct User-IDs:
|
||||
|
||||
```java
|
||||
UserId nameAndEMail = UserId.nameAndEmail("Jane Doe", "jane@pgpainless.org");
|
||||
assertEquals("Jane Doe <jane@pgpainless.org>", nameAndEmail.toString()):
|
||||
|
||||
UserId onlyEmail = UserId.onlyEmail("john@pgpainless.org");
|
||||
assertEquals("<john@pgpainless.org>", onlyEmail.toString());
|
||||
|
||||
UserId full = UserId.newBuilder()
|
||||
.withName("Peter Pattern")
|
||||
.withEmail("peter@pgpainless.org")
|
||||
.withComment("Work Address")
|
||||
.build();
|
||||
assertEquals("Peter Pattern <peter@pgpainless.org> [Work Address]", full.toString());
|
||||
```
|
Loading…
Reference in a new issue