mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-22 10:57:58 +01:00
Initial sphinx-based documentation
This commit is contained in:
parent
762391659e
commit
16c44e670e
13 changed files with 3284 additions and 92 deletions
92
ECOSYSTEM.md
92
ECOSYSTEM.md
|
@ -1,92 +0,0 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: 2022 Paul Schaub <info@pgpainless.org>
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
# Ecosystem
|
||||
|
||||
PGPainless consists of an ecosystem of different libraries and projects.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph SOP-JAVA
|
||||
sop-java-picocli-->sop-java
|
||||
end
|
||||
subgraph PGPAINLESS
|
||||
pgpainless-sop-->pgpainless-core
|
||||
pgpainless-sop-->sop-java
|
||||
pgpainless-cli-->pgpainless-sop
|
||||
pgpainless-cli-->sop-java-picocli
|
||||
end
|
||||
subgraph WKD-JAVA
|
||||
wkd-java-cli-->wkd-java
|
||||
wkd-test-suite-->wkd-java
|
||||
wkd-test-suite-->pgpainless-core
|
||||
end
|
||||
subgraph CERT-D-JAVA
|
||||
pgp-cert-d-java-->pgp-certificate-store
|
||||
pgp-cert-d-java-jdbc-sqlite-lookup-->pgp-cert-d-java
|
||||
end
|
||||
subgraph CERT-D-PGPAINLESS
|
||||
pgpainless-cert-d-->pgpainless-core
|
||||
pgpainless-cert-d-->pgp-cert-d-java
|
||||
pgpainless-cert-d-cli-->pgpainless-cert-d
|
||||
pgpainless-cert-d-cli-->pgp-cert-d-java-jdbc-sqlite-lookup
|
||||
end
|
||||
subgraph VKS-JAVA
|
||||
vks-java-cli-->vks-java
|
||||
end
|
||||
subgraph PGPEASY
|
||||
pgpeasy-->pgpainless-cli
|
||||
pgpeasy-->wkd-java-cli
|
||||
pgpeasy-->vks-java-cli
|
||||
pgpeasy-->pgpainless-cert-d-cli
|
||||
end
|
||||
wkd-java-cli-->pgpainless-cert-d
|
||||
wkd-java-->pgp-certificate-store
|
||||
```
|
||||
|
||||
## [PGPainless](https://github.com/pgpainless/pgpainless)
|
||||
|
||||
The main repository contains the following components:
|
||||
|
||||
* `pgpainless-core` - core implementation - powerful, yet easy to use OpenPGP API
|
||||
* `pgpainless-sop` - super simple OpenPGP implementation. Drop-in for `sop-java`
|
||||
* `pgpainless-cli` - SOP CLI implementation using PGPainless
|
||||
|
||||
## [SOP-Java](https://github.com/pgpainless/sop-java)
|
||||
|
||||
An API definition and CLI implementation of the [Stateless OpenPGP Protocol](https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-03.html).
|
||||
|
||||
* `sop-java` - generic OpenPGP API definition
|
||||
* `sop-java-picocli` - Abstract CLI implementation for `sop-java`
|
||||
|
||||
## [WKD-Java](https://github.com/pgpainless/wkd-java)
|
||||
|
||||
Implementation of the [Web Key Directory](https://www.ietf.org/archive/id/draft-koch-openpgp-webkey-service-13.html).
|
||||
|
||||
* `wkd-java` - abstract WKD discovery implementation
|
||||
* `wkd-java-cli` - CLI application implementing WKD discovery using PGPainless
|
||||
* `wkd-test-suite` - Generator for test vectors for testing WKD implementations
|
||||
|
||||
## [VKS-Java](https://github.com/pgpainless/vks-java)
|
||||
|
||||
Client-side API for communicating with Verifying Key Servers, such as https://keys.openpgp.org/.
|
||||
|
||||
* `vks-java` - VKS client implementation
|
||||
|
||||
## [Cert-D-Java](https://github.com/pgpainless/cert-d-java)
|
||||
|
||||
Implementations of the [Shared OpenPGP Certificate Directory specification](https://sequoia-pgp.gitlab.io/pgp-cert-d/).
|
||||
|
||||
* `pgp-certificate-store` - abstract definitions of OpenPGP certificate stores
|
||||
* `pgp-cert-d-java` - implementation of `pgp-certificate-store` following the PGP-CERT-D spec.
|
||||
* `pgp-cert-d-java-jdbc-sqlite-lookup` - subkey lookup using sqlite database
|
||||
|
||||
## [Cert-D-PGPainless](https://github.com/pgpainless/cert-d-pgpainless)
|
||||
|
||||
Implementation of the [Shared OpenPGP Certificate Directory specification](https://sequoia-pgp.gitlab.io/pgp-cert-d/) using PGPainless.
|
||||
|
||||
* `pgpainless-cert-d` - PGPainless-based implementation of `pgp-cert-d-java`.
|
||||
* `pgpainless-cert-d-cli` - CLI frontend for `pgpainless-cert-d`.
|
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
16
docs/README.md
Normal file
16
docs/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# User Guide for PGPainless
|
||||
|
||||
## Build the Guide
|
||||
|
||||
```shell
|
||||
$ make {html|epub|latexpdf}
|
||||
```
|
||||
|
||||
Note: Building requires `mermaid-cli` to be installed in this directory:
|
||||
```shell
|
||||
$ # Move here
|
||||
$ cd pgpainless/docs
|
||||
$ npm install @mermaid-js/mermaid-cli
|
||||
```
|
||||
|
||||
TODO: This is ugly. Install mermaid-cli globally? Perhaps point to user-installed mermaid-cli in conf.py's mermaid_cmd
|
35
docs/make.bat
Normal file
35
docs/make.bat
Normal file
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
2626
docs/package-lock.json
generated
Normal file
2626
docs/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
5
docs/package.json
Normal file
5
docs/package.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@mermaid-js/mermaid-cli": "^9.1.3"
|
||||
}
|
||||
}
|
53
docs/source/conf.py
Normal file
53
docs/source/conf.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import os
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
|
||||
# -- Project information
|
||||
|
||||
project = 'PGPainless'
|
||||
copyright = '2022, Paul Schaub'
|
||||
author = 'Paul Schaub'
|
||||
|
||||
# https://protips.readthedocs.io/git-tag-version.html
|
||||
latest_tag = os.popen('git describe --abbrev=0').read().strip()
|
||||
release = latest_tag
|
||||
version = release
|
||||
|
||||
myst_substitutions = {
|
||||
"repo_host" : "codeberg.org"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
# -- General configuration
|
||||
|
||||
extensions = [
|
||||
'myst_parser',
|
||||
'sphinxcontrib.mermaid',
|
||||
'sphinx.ext.duration',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.autosummary',
|
||||
]
|
||||
|
||||
source_suffix = ['.rst', '.md']
|
||||
|
||||
myst_enable_extensions = [
|
||||
'colon_fence',
|
||||
'substitution',
|
||||
]
|
||||
|
||||
myst_heading_anchors = 3
|
||||
|
||||
templates_path = ['_templates']
|
||||
|
||||
# -- Options for HTML output
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# -- Options for EPUB output
|
||||
#epub_show_urls = 'footnote'
|
||||
|
||||
mermaid_cmd = "./node_modules/.bin/mmdc"
|
||||
mermaid_output_format = 'png'
|
||||
mermaid_params = ['--theme', 'default', '--width', '800', '--backgroundColor', 'transparent']
|
85
docs/source/ecosystem.md
Normal file
85
docs/source/ecosystem.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
# The PGPainless Ecosystem
|
||||
|
||||
PGPainless consists of an ecosystem of different libraries and projects.
|
||||
|
||||
The diagram below shows, how the different projects relate to one another.
|
||||
|
||||
```{mermaid}
|
||||
flowchart LR
|
||||
subgraph SOP-JAVA
|
||||
sop-java-picocli-->sop-java
|
||||
end
|
||||
subgraph PGPAINLESS
|
||||
pgpainless-sop-->pgpainless-core
|
||||
pgpainless-sop-->sop-java
|
||||
pgpainless-cli-->pgpainless-sop
|
||||
pgpainless-cli-->sop-java-picocli
|
||||
end
|
||||
subgraph WKD-JAVA
|
||||
wkd-java-cli-->wkd-java
|
||||
wkd-test-suite-->wkd-java
|
||||
wkd-test-suite-->pgpainless-core
|
||||
end
|
||||
subgraph CERT-D-JAVA
|
||||
pgp-cert-d-java-->pgp-certificate-store
|
||||
pgp-cert-d-java-jdbc-sqlite-lookup-->pgp-cert-d-java
|
||||
end
|
||||
subgraph CERT-D-PGPAINLESS
|
||||
pgpainless-cert-d-->pgpainless-core
|
||||
pgpainless-cert-d-->pgp-cert-d-java
|
||||
pgpainless-cert-d-cli-->pgpainless-cert-d
|
||||
pgpainless-cert-d-cli-->pgp-cert-d-java-jdbc-sqlite-lookup
|
||||
end
|
||||
subgraph VKS-JAVA
|
||||
vks-java-cli-->vks-java
|
||||
end
|
||||
subgraph PGPEASY
|
||||
pgpeasy-->pgpainless-cli
|
||||
pgpeasy-->wkd-java-cli
|
||||
pgpeasy-->vks-java-cli
|
||||
pgpeasy-->pgpainless-cert-d-cli
|
||||
end
|
||||
wkd-java-cli-->pgpainless-cert-d
|
||||
wkd-java-->pgp-certificate-store
|
||||
```
|
||||
|
||||
## Libraries and Tools
|
||||
|
||||
* {{ '[PGPainless](https://{}/pgpainless/pgpainless)'.format(repo_host) }}
|
||||
The main repository contains the following components:
|
||||
* `pgpainless-core` - core implementation - powerful, yet easy to use OpenPGP API
|
||||
* `pgpainless-sop` - super simple OpenPGP implementation. Drop-in for `sop-java`
|
||||
* `pgpainless-cli` - SOP CLI implementation using PGPainless
|
||||
|
||||
* {{ '[SOP-Java](https://{}/pgpainless/sop-java)'.format(repo_host) }}
|
||||
An API definition and CLI implementation of the [Stateless OpenPGP Protocol](https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/) (SOP).
|
||||
Consumers of the SOP API can simply depend on `sop-java` and then switch out the backend as they wish.
|
||||
Read more about the [SOP](sop) protocol here.
|
||||
* `sop-java` - generic OpenPGP API definition
|
||||
* `sop-java-picocli` - CLI frontend for `sop-java`
|
||||
|
||||
* {{ '[WKD-Java](https://{}/pgpainless/wkd-java)'.format(repo_host) }}
|
||||
Implementation of the [Web Key Directory](https://www.ietf.org/archive/id/draft-koch-openpgp-webkey-service-13.html).
|
||||
* `wkd-java` - generic WKD discovery implementation
|
||||
* `wkd-java-cli` - CLI frontend for WKD discovery using PGPainless
|
||||
* `wkd-test-suite` - Generator for test vectors for testing WKD implementations
|
||||
|
||||
* {{ '[VKS-Java](https://{}/pgpainless/vks-java)'.format(repo_host) }}
|
||||
Client-side API for communicating with Verifying Key Servers, such as https://keys.openpgp.org/.
|
||||
* `vks-java` - VKS client implementation
|
||||
* `vks-java-cli` - CLI frontend for `vks-java`
|
||||
|
||||
* {{ '[Cert-D-Java](https://{}/pgpainless/cert-d-java)'.format(repo_host) }}
|
||||
Implementations of the [Shared OpenPGP Certificate Directory specification](https://sequoia-pgp.gitlab.io/pgp-cert-d/).
|
||||
* `pgp-certificate-store` - abstract definitions of OpenPGP certificate stores
|
||||
* `pgp-cert-d-java` - implementation of `pgp-certificate-store` following the PGP-CERT-D spec
|
||||
* `pgp-cert-d-java-jdbc-sqlite-lookup` - subkey lookup using sqlite database
|
||||
|
||||
* {{ '[Cert-D-PGPainless](https://{}/pgpainless/cert-d-pgpainless)'.format(repo_host) }}
|
||||
Implementation of the [Shared OpenPGP Certificate Directory specification](https://sequoia-pgp.gitlab.io/pgp-cert-d/) using PGPainless.
|
||||
* `pgpainless-cert-d` - PGPainless-based implementation of `pgp-cert-d-java`
|
||||
* `pgpainless-cert-d-cli` - CLI frontend for `pgpainless-cert-d`
|
||||
|
||||
* {{ '[PGPeasy](https://{}/pgpainless/pgpeasy)'.format(repo_host) }}
|
||||
Prototypical, comprehensive OpenPGP CLI application
|
||||
* `pgpeasy` - CLI application
|
25
docs/source/index.rst
Normal file
25
docs/source/index.rst
Normal file
|
@ -0,0 +1,25 @@
|
|||
PGPainless - Painless OpenPGP
|
||||
=============================
|
||||
|
||||
**OpenPGP** (`RFC 4480 <https://datatracker.ietf.org/doc/rfc4880/>`_) is an Internet Standard mostly used for email encryption.
|
||||
It provides mechanisms to ensure *confidentiality*, *integrity* and *authenticity* of messages.
|
||||
However, OpenPGP can also be used for other purposes, such as secure messaging or as a signature mechanism for software distribution.
|
||||
|
||||
**PGPainless** strives to improve the (currently pretty dire) state of the ecosystem of Java libraries and tooling for OpenPGP.
|
||||
|
||||
The library focuses on being easy and intuitive to use without getting into your way.
|
||||
Common functions such as creating keys, encrypting data, and so on are implemented using a builder structure that guides you through the necessary steps.
|
||||
|
||||
Internally, it is based on `Bouncy Castles <https://www.bouncycastle.org/java.html>`_ mighty, but low-level OpenPGP API.
|
||||
PGPainless' goal is to empower you to use OpenPGP without needing to write all the boilerplate code required by Bouncy Castle.
|
||||
It aims to be secure by default while allowing customization if required.
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
|
||||
quickstart.md
|
||||
ecosystem.md
|
||||
sop.md
|
27
docs/source/pgpainless-core/quickstart.md
Normal file
27
docs/source/pgpainless-core/quickstart.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
## PGPainless API with pgpainless-core
|
||||
|
||||
Coming soon.
|
||||
|
||||
### Setup
|
||||
bla
|
||||
|
||||
### Generate a Key
|
||||
bla
|
||||
|
||||
### Extract a Certificate
|
||||
bla
|
||||
|
||||
### Apply / Remove ASCII Armor
|
||||
bla
|
||||
|
||||
### Encrypt a Message
|
||||
bla
|
||||
|
||||
### Decrypt a Message
|
||||
bla
|
||||
|
||||
### Sign a Message
|
||||
bla
|
||||
|
||||
### Verify a Signature
|
||||
bla
|
369
docs/source/pgpainless-sop/quickstart.md
Normal file
369
docs/source/pgpainless-sop/quickstart.md
Normal file
|
@ -0,0 +1,369 @@
|
|||
## SOP API with pgpainless-sop
|
||||
|
||||
The Stateless OpenPGP Protocol (SOP) defines a simplistic interface for the most important OpenPGP operations.
|
||||
It allows you to encrypt, decrypt, sign and verify messages, generate keys and add/remove ASCII armor from data.
|
||||
However, it does not yet provide tools for key management.
|
||||
Furthermore, the implementation is deciding for you, which (secure) algorithms to use, and it doesn't let you
|
||||
change those.
|
||||
|
||||
If you want to read more about the background of the SOP protocol, there is a [whole chapter](../sop) dedicated to it.
|
||||
|
||||
### Setup
|
||||
|
||||
PGPainless' releases are published to and can be fetched from Maven Central.
|
||||
To get started, you first need to include `pgpainless-sop` in your projects build script.
|
||||
```
|
||||
// If you use Gradle
|
||||
...
|
||||
dependencies {
|
||||
...
|
||||
implementation "org.pgpainless:pgpainless-sop:XYZ"
|
||||
...
|
||||
}
|
||||
|
||||
// If you use Maven
|
||||
...
|
||||
<dependencies>
|
||||
...
|
||||
<dependency>
|
||||
<groupId>org.pgpainless</groupId>
|
||||
<artifactId>pgpainless-sop</artifactId>
|
||||
<version>XYZ</version>
|
||||
</dependency>
|
||||
...
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
:::{important}
|
||||
Replace `XYZ` with the current version, e.g. {{ env.config.version }}!
|
||||
:::
|
||||
|
||||
The entry point to the API is the `SOP` interface, for which `pgpainless-sop` provides a concrete implementation
|
||||
`SOPImpl`.
|
||||
|
||||
```java
|
||||
// Instantiate the API
|
||||
SOP sop = new SOPImpl();
|
||||
```
|
||||
|
||||
Now you are ready to go!
|
||||
|
||||
### Generate a Key
|
||||
|
||||
To generate a new OpenPGP key, the method `SOP.generateKey()` is your friend:
|
||||
|
||||
```java
|
||||
// generate key
|
||||
byte[] keyBytes = sop.generateKey()
|
||||
.userId("John Doe <john.doe@pgpainless.org>")
|
||||
.withKeyPassword("f00b4r")
|
||||
.generate()
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
The call `userId(String userId)` can be called multiple times to add multiple user-ids to the key, but it MUST
|
||||
be called at least once.
|
||||
The argument given in the first invocation will become the keys primary user-id.
|
||||
|
||||
Optionally, the key can be protected with a password by calling `withKeyPassword(String password)`.
|
||||
If this method is not called, the key will be unprotected.
|
||||
|
||||
The `generate()` method call generates the key and returns a `Ready` object.
|
||||
This in turn can be used to write the result to a stream via `writeTo(OutputStream out)`, or to get the result
|
||||
as bytes via `getBytes()`.
|
||||
In both cases, the resulting output will be the UTF8 encoded, ASCII armored OpenPGP secret key.
|
||||
|
||||
To disable ASCII armoring, call `noArmor()` before calling `generate()`.
|
||||
|
||||
At the time of writing, the resulting OpenPGP secret key will consist of a certification-capable 256-bits
|
||||
ed25519 EdDSA primary key, a 256-bits ed25519 EdDSA subkey used for signing, as well as a 256-bits X25519
|
||||
ECDH subkey for encryption.
|
||||
|
||||
The whole key does not have an expiration date set.
|
||||
|
||||
### Extract a Certificate
|
||||
|
||||
Now that you generated your secret key, you probably want to share the public key with your contacts.
|
||||
To extract the OpenPGP public key (which we will call *certificate* from now on) from the secret key,
|
||||
use the `SOP.extractCert()` method call:
|
||||
|
||||
```java
|
||||
// extract certificate
|
||||
byte[] certificateBytes = sop.extractCert()
|
||||
.key(keyBytes)
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
The `key(_)` method either takes a byte array (like in the example), or an `InputStream`.
|
||||
In both cases it returns another `Ready` object from which the certificate can be accessed, either via
|
||||
`writeTo(OutputStream out)` or `getBytes()`.
|
||||
|
||||
By default, the resulting certificate will be ASCII armored, regardless of whether the input key was armored or not.
|
||||
To disable ASCII armoring, call `noArmor()` before calling `key(_)`.
|
||||
|
||||
In our example, `certificateBytes` can now safely be shared with anyone.
|
||||
|
||||
### Apply / Remove ASCII Armor
|
||||
|
||||
Perhaps you want to print your secret key onto a piece of paper for backup purposes,
|
||||
but you accidentally called `noArmor()` when generating the key.
|
||||
|
||||
To add ASCII armor to some binary OpenPGP data, the `armor()` API can be used:
|
||||
|
||||
```java
|
||||
// wrap data in ASCII armor
|
||||
byte[] armoredData = sop.armor()
|
||||
.data(binaryData)
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
The `data(_)` method can either be called by providing a byte array, or an `InputStream`.
|
||||
|
||||
:::{note}
|
||||
There is a `label(ArmorLabel label)` method, which could theoretically be used to define the label used in the
|
||||
ASCII armor header.
|
||||
However, this method is not (yet?) supported by `pgpainless-sop` and will currently throw an `UnsupportedOption`
|
||||
exception.
|
||||
Instead, the implementation will figure out the data type and set the respective label on its own.
|
||||
:::
|
||||
|
||||
To remove ASCII armor from armored data, simply use the `dearmor()` API:
|
||||
|
||||
```java
|
||||
// remove ASCII armor
|
||||
byte[] binaryData = sop.unarmor()
|
||||
.data(armoredData)
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
Once again, the `data(_)` method can be called either with a byte array or an `InputStream` as argument.
|
||||
|
||||
If the input data is not validly armored OpenPGP data, the `data(_)` method call will throw a `BadData` exception.
|
||||
|
||||
### Encrypt a Message
|
||||
|
||||
Now lets get to the juicy part and finally encrypt a message!
|
||||
In this example, we will assume that Alice is the sender that wants to send a message to Bob.
|
||||
Beforehand, Alice acquired Bobs certificate, e.g. by fetching it from a key server.
|
||||
|
||||
To encrypt a message, you can make use of the `encrypt()` API:
|
||||
|
||||
```java
|
||||
// encrypt and sign a message
|
||||
byte[] aliceKey = ...; // Alice' secret key
|
||||
byte[] aliceCert = ...; // Alice' certificate (e.g. via extractCert())
|
||||
byte[] bobCert = ...; // Bobs certificate
|
||||
|
||||
byte[] plaintext = "Hello, World!\n".getBytes(); // plaintext
|
||||
|
||||
byte[] ciphertext = sop.encrypt()
|
||||
// encrypt for each recipient
|
||||
.withCert(bobCert)
|
||||
.withCert(aliceCert)
|
||||
// Optionally: Sign the message
|
||||
.signWith(aliceKey)
|
||||
.withKeyPassword("sw0rdf1sh") // if signing key is protected
|
||||
// provide the plaintext
|
||||
.plaintext(plaintext)
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
Here you encrypt the message for each recipient (Alice probably wants to be able to decrypt the message too!)
|
||||
by calling `withCert(_)` with the recipients certificate as argument. It does not matter, if the certificate
|
||||
is ASCII armored or not, and the method can either be called with a byte array or an `InputStream` as argument.
|
||||
|
||||
The API not only supports asymmetric encryption via OpenPGP certificates, but it can also encrypt messages
|
||||
symmetrically using one or more passwords. Both mechanisms can even be used together in the same message!
|
||||
To (additionally or exclusively) encrypt the message for a password, simply call `withPassword(String password)`
|
||||
before the `plaintext(_)` method call.
|
||||
|
||||
It is recommended (but not required) to sign encrypted messages.
|
||||
In order to sign the message before encryption is applied, call `signWith(_)` with the signing key as argument.
|
||||
This method call can be repeated multiple times to sign the message with multiple signing keys.
|
||||
|
||||
If any keys used for signing are password protected, you need to provide the signing key password via
|
||||
`withKeyPassword(_)`.
|
||||
It does not matter in which order signing keys and key passwords are provided, the implementation will figure out
|
||||
matches on its own. If different key passwords are used, the `withKeyPassword(_)` method can be called multiple times.
|
||||
|
||||
By default, the encrypted message will be ASCII armored. To disable ASCII armor, call `noArmor()` before the
|
||||
`plaintext(_)` method call.
|
||||
|
||||
Lastly, you need to provide the plaintext by calling `plaintext(_)` with either a byte array or an `InputStream`
|
||||
as argument.
|
||||
The ciphertext can then be accessed from the resulting `Ready` object as usual.
|
||||
|
||||
### Decrypt a Message
|
||||
|
||||
Now let's switch perspective and help Bob decrypt the message from Alice.
|
||||
|
||||
Decrypting encrypted messages is done in a similar fashion using the `decrypt()` API:
|
||||
|
||||
```java
|
||||
// decrypt a message and verify its signature(s)
|
||||
byte[] aliceCert = ...; // Alice' certificate
|
||||
byte[] bobKey = ...; // Bobs secret key
|
||||
byte[] bobCert = ...; // Bobs certificate
|
||||
|
||||
byte[] ciphertext = ...; // the encrypted message
|
||||
|
||||
ReadyWithResult<DecryptionResult> readyWithResult = sop.decrypt()
|
||||
.withKey(bobKey)
|
||||
.verifyWith(aliceCert)
|
||||
.withKeyPassword("password123") // if decryption key is protected
|
||||
.ciphertext(ciphertext);
|
||||
```
|
||||
|
||||
The `ReadyWithResult<DecryptionResult>` can now be processed in two different ways, depending on whether you want the
|
||||
plaintext as bytes or simply write it out to an `OutputStream`.
|
||||
|
||||
To get the plaintext bytes directly, you shall proceed as follows:
|
||||
|
||||
```java
|
||||
ByteArrayAndResult<DecryptionResult> bytesAndResult = readyWithResult.toByteArrayAndResult();
|
||||
DecryptionResult result = bytesAndResult.getResult();
|
||||
byte[] plaintext = bytesAndResult.getBytes();
|
||||
```
|
||||
|
||||
If you instead want to write the plaintext out to an `OutputStream`, the following code can be used:
|
||||
|
||||
```java
|
||||
OutputStream out = ...;
|
||||
DecryptionResult result = readyWithResult.writeTo(out);
|
||||
```
|
||||
|
||||
Note, that in both cases you acquire a `DecryptionResult` object. This contains information about the message,
|
||||
such as which signatures could successfully be verified.
|
||||
|
||||
If you provided the senders certificate for the purpose of signature verification via `verifyWith(_)`, you now
|
||||
probably want to check, if the message was actually signed by the sender by checking `result.getVerifications()`.
|
||||
|
||||
:::{note}
|
||||
Signature verification will be discussed in more detail in section [](#verify-a-signature)
|
||||
:::
|
||||
|
||||
If the message was encrypted symmetrically using a password, you can also decrypt is symmetrically by calling
|
||||
`withPassword(String password)` before the `ciphertext(_)` method call. This method call can be repeated multiple
|
||||
times. The implementation will try different passwords until it finds a matching one.
|
||||
|
||||
### Sign a Message
|
||||
|
||||
There are three different main ways of signing a message:
|
||||
* Inline Signatures
|
||||
* Cleartext Signatures
|
||||
* Detached Signatures
|
||||
|
||||
An inline-signature will be part of the message itself (e.g. like with messages that are encrypted *and* signed).
|
||||
Inline-signed messages are not human-readable without prior processing.
|
||||
|
||||
A cleartext signature makes use of the [cleartext signature framework](https://datatracker.ietf.org/doc/html/rfc4880#section-7).
|
||||
Messages signed in this way do have an ASCII armor header and footer, yet the content of the message is still
|
||||
human-readable without special software.
|
||||
|
||||
Lastly, a detached signature can be distributed as an extra file alongside the message without altering it.
|
||||
This is useful if the plaintext itself cannot be modified (e.g. if a binary file is signed).
|
||||
|
||||
The SOP API can generate all of those signature types.
|
||||
|
||||
#### Inline-Signatures
|
||||
|
||||
Let's start with an inline signature:
|
||||
|
||||
```java
|
||||
byte[] signingKey = ...;
|
||||
byte[] message = ...;
|
||||
|
||||
byte[] inlineSignedMessage = sop.inlineSign()
|
||||
.mode(InlineSignAs.Text) // or 'Binary'
|
||||
.key(signingKey)
|
||||
.withKeyPassword("fnord")
|
||||
.data(message)
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
You can choose between two different signature formats which can be set using `mode(InlineSignAs mode)`.
|
||||
The default value is `Binary`. You can also set it to `Text` which signals to the receiver that the data is
|
||||
UTF8 text.
|
||||
|
||||
:::{note}
|
||||
For inline signatures, do NOT set the `mode()` to `CleartextSigned`, as that will create message which uses the
|
||||
cleartext signature framework (see further below).
|
||||
:::
|
||||
|
||||
You must provide at least one signing key using `key(_)` in order to be able to sign the message.
|
||||
|
||||
If any key is password protected, you need to provide its password using `withKeyPassword(_)` which
|
||||
can be called multiple times to provide multiple passwords.
|
||||
|
||||
Once you provide the plaintext using `data(_)` with either a byte array or an `InputStream` as argument,
|
||||
you will get a `Ready` object back, from which the signed message can be retrieved as usual.
|
||||
|
||||
By default, the signed message will be ASCII armored. This can be disabled by calling `noArmor()`
|
||||
before the `data(_)` method call.
|
||||
|
||||
#### Cleartext Signatures
|
||||
|
||||
A cleartext-signed message can be generated in a similar way to an inline-signed message, however,
|
||||
there are is one subtle difference:
|
||||
|
||||
```java
|
||||
byte[] signingKey = ...;
|
||||
byte[] message = ...;
|
||||
|
||||
byte[] cleartextSignedMessage = sop.inlineSign()
|
||||
.mode(InlineSignAs.CleartextSigned) // This MUST be set
|
||||
.key(signingKey)
|
||||
.withKeyPassword("fnord")
|
||||
.data(message)
|
||||
.getBytes();
|
||||
```
|
||||
|
||||
:::{important}
|
||||
In order to produce a cleartext-signed message, the signature mode MUST be set to `CleartextSigned`
|
||||
by calling `mode(InlineSignAs.CleartextSigned)`.
|
||||
:::
|
||||
|
||||
:::{note}
|
||||
Calling `noArmor()` will have no effect for cleartext-signed messages, so such method call will be ignored.
|
||||
:::
|
||||
|
||||
#### Detached Signatures
|
||||
|
||||
As the name suggests, detached signatures are detached from the message itself and can be distributed separately.
|
||||
|
||||
To produce a detached signature, the `detachedSign()` API is used:
|
||||
|
||||
```java
|
||||
byte[] signingKey = ...;
|
||||
byte[] message = ...;
|
||||
|
||||
ReadyWithResult<SigningResult> readyWithResult = sop.detachedSign()
|
||||
.key(signingKey)
|
||||
.withKeyPassword("fnord")
|
||||
.data(message);
|
||||
```
|
||||
|
||||
Here you have the choice, how you want to write out the signature.
|
||||
If you want to write the signature to an `OutputStream`, you can do the following:
|
||||
|
||||
```java
|
||||
OutputStream out = ...;
|
||||
SigningResult result = readyWithResult.writeTo(out);
|
||||
```
|
||||
|
||||
If instead you want to get the signature as a byte array, do this instead:
|
||||
|
||||
```java
|
||||
ByteArrayAndResult<SigningResult> bytesAndResult = readyWithResult.toByteArrayAndResult();
|
||||
SigningResult result = bytesAndResult.getResult();
|
||||
byte[] detachedSignature = bytesAndResult.getBytes();
|
||||
```
|
||||
|
||||
In any case, the detached signature can now be distributed alongside the original message.
|
||||
|
||||
By default, the resulting detached signature will be ASCII armored. This can be disabled by calling `noArmor()`
|
||||
prior to calling `data(_)`.
|
||||
|
||||
The `SigningResult` object you got back in both cases contains information about the signature.
|
||||
|
||||
### Verify a Signature
|
20
docs/source/quickstart.md
Normal file
20
docs/source/quickstart.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Quickstart Guide
|
||||
|
||||
In this guide, we will get you started with OpenPGP using PGPainless as quickly as possible.
|
||||
|
||||
At first though, you need to decide which API you want to use;
|
||||
|
||||
* PGPainless' core API is powerful and heavily customizable
|
||||
* The SOP API is a bit less powerful, but *dead* simple to use
|
||||
|
||||
The SOP API is the recommended way to go if you just want to get started already.
|
||||
|
||||
In case you need more technical documentation, Javadoc can be found in the following places:
|
||||
* For the core API: {{ '[pgpainless-core](https://javadoc.io/doc/org.pgpainless/pgpainless-core/{}/index.html)'.format(env.config.version) }}
|
||||
* For the SOP API: {{ '[pgpainless-sop](https://javadoc.io/doc/org.pgpainless/pgpainless-sop/{}/index.html)'.format(env.config.version) }}
|
||||
|
||||
```{include} pgpainless-sop/quickstart.md
|
||||
```
|
||||
|
||||
```{include} pgpainless-core/quickstart.md
|
||||
```
|
3
docs/source/sop.md
Normal file
3
docs/source/sop.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Stateless OpenPGP Protocol (SOP)
|
||||
|
||||
Lorem ipsum dolor sit amet.
|
Loading…
Reference in a new issue