Skip to content
This repository has been archived by the owner on Mar 16, 2023. It is now read-only.

Commit

Permalink
legacy-less publication on github
Browse files Browse the repository at this point in the history
  • Loading branch information
yahesh committed Aug 10, 2017
1 parent 45b51ed commit 7da09f5
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 240 deletions.
8 changes: 8 additions & 0 deletions .htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<IfModule mod_rewrite.c>
RewriteEngine On

RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /index.php [L]
</IfModule>
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# 0.11b0 (2017-08-10)

* version bump for legacy-less publication on github
* **Beware:** Due to security concerns the previously introduced GnuPG PECL interface has been forcecfully deactivated. This change may break installations that currently rely on the functionality of the GnuPG PECL interface.

# 0.10b2 (2017-08-10)

* activated ENABLE_PASSWORD_PROTECTION option by default as the feature has proven to be stable
* deactivated LOG_IP_ADDRESS option by default to promote data privacy
* removed SUPPORT_LEGACY_LINKS option because the codebase does not generate legacy links for almost a year now
* removed code that handled legacy links and has become obsolete with the removal of the SUPPORT_LEGACY_LINKS option
* forcefully deactivated the GnuPG PECL interface because https://github.com/php-gnupg/php-gnupg/issues/9 is not handled properly
* changed README.md to reflect the forcful deactivation of the GnuPG PECL interface which may break installations

# 0.10b1 (2016-12-19)

* enforced strict base64 decoding
Expand Down
48 changes: 8 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Shared-Secrets

Shared-Secrets is an application that helps you to simply share one-time secrets over the web. Typically when you do not have the possibility to open an encrypted communication channel (e.g. GPG-encrypted mail) to transfer an important information you have to resort to unencrypted means of communication - e.g. SMS, unencrypted e-mail, telephone, etc.
Shared-Secrets is an application that helps you to simply share one-time secrets over the web. Typically when you do not have the possibility to open an encrypted communication channel (e.g. GPG-encrypted mail) to transfer a sensitive information you have to resort to unencrypted means of communication - e.g. SMS, unencrypted e-mail, telephone, etc.

Using the Shared-Secrets service allows you to transfer the actual secret in an encrypted form. Retrieving the secret is as simple as following a link. In contrast to other secret sharing services, Shared-Secrets does not store the secret on the server, but puts the encrypted secret into the link that you share with the desired recipient. That means that the comprise of a Shared-Secrets server does not automatically compromise all of the shared secrets.
Using the Shared-Secrets service allows you to transfer the actual secret in an encrypted form. Retrieving the secret is as simple as following a link. In contrast to other secret sharing services, Shared-Secrets does not store the secret on the server, but puts the encrypted secret into the link that you share with the desired recipient. That means that the compromise of a Shared-Secrets server does not automatically compromise all of the shared secrets.

Secrets can only be retrieved once. Further retrievals are rejected by matching the secret against the fingerprints of secrets that have been retrieved before. By disallowing repeating retrievals of a secret, it is at least possible to detect when the confidentiality of a secret has been compromised.
Secrets can only be retrieved once. Further retrievals are rejected by matching the encrypted secret against the fingerprints of the secrets that have been retrieved before. By disallowing repeating retrievals of a secret, it is at least possible to detect when the confidentiality of a secret sharing link has been compromised.

To protect your secret from getting known by the server or an attacker, you can additionally protect the secret with a password before sharing it. The secret will be encrypted and decrypted locally without an interaction with the server. You can provide the chosen password to the recipient through a second communication channel to prevent an attacker that is able to control one communication channel from compromising the confidentiallity of your secret.

Expand All @@ -16,7 +16,7 @@ Simply enter your secret on the default page of the Shared-Secrets service. You

Secret sharing links can also be created by using a simple POST request:
```
curl -X POST -d "secret=<secret>&plain" https://example.com/
curl -X POST -d "plain&secret=<secret>" https://example.com/
```

### Read a Secret
Expand All @@ -33,7 +33,7 @@ curl -X POST -d "plain" <secret sharing link>

### Requirements

Shared-Secrets is based on MariaDB 10.0, Nginx 1.10 and PHP 7.0, but should also work with MySQL, Apache and earlier versions of PHP. GPG encryption is supported through the [GnuPG PECL package](https://pecl.php.net/package/gnupg) as well as through directly calling the gpg binary. Using the GnuPG PECL package is the prefered mechanism due to its cleaner interface. If you want to use the GnuPG PECL package support of the Shared-Secrets service in a chroot environment you have to set up your chroot environment properly - this does not seem to be easy.
Shared-Secrets is based on MariaDB 10.0, Nginx 1.10 and PHP 7.0, but should also work with MySQL, Apache and earlier versions of PHP. GPG encryption is supported by directly calling the gpg binary. Previously, using the [GnuPG PECL package](https://pecl.php.net/package/gnupg) has been prefered mechanism due to its cleaner interface - however this interface is currently forcefully deactivated due to security concerns.

### Nginx Setup

Expand Down Expand Up @@ -79,7 +79,7 @@ add_header X-XSS-Protection "1; mode=block";

### MariaDB Setup

Shared-Secrets uses a single-table database to store who did retrieve which secret at what point in time. No actual secret content is stored. (The logging of IP addresses can be disabled through the configuration parameter LOG_IP_ADDRESS.):
Shared-Secrets uses a single-table database to store who did retrieve which secret at what point in time. No actual secret content is stored. (The logging of IP addresses is disabled through the configuration parameter LOG_IP_ADDRESS by default.):
```
CREATE TABLE secrets ( fingerprint VARCHAR(64) PRIMARY KEY, ip VARCHAR(46), time TIMESTAMP );
```
Expand All @@ -92,7 +92,7 @@ You have to have a somewhat recent GPG version installed on the server. Furtherm
gpg --gen-key
# read the fingerprint of the generated key, replace <email> with the e-mail address that has been used for the key,
# the fingerprint will be shown with spaces for better readability
# the fingerprint will be shown with spaces for better readability - these have to be removed when configuring the software
gpg --with-fingerprint --list-keys <email>
# export the private encryption subkey and the public key
Expand All @@ -104,41 +104,10 @@ sudo -u www-data -H gpg --import ./private.asc
sudo -u www-data -H gpg --import ./public.asc
```

### PHP Setup

**Beware:** Due to a serious bug in the GnuPG PECL package we ask to use the non-PECL setup.

To use the [GnuPG PECL package](https://pecl.php.net/package/gnupg) it has to be installed and activated on the server. The following steps are based on Ubuntu 16.04 LTS and only serve as an example for the installation and activation of the GnuPG PECL package:
```
# install PHP PEAR/PECL
sudo apt-get install php-pear
# install the PHP development tools
sudo apt-get install php7.0-dev
# install the GPGME development package, see https://www.gnupg.org/related_software/gpgme/index.html
sudo apt-get install libgpgme11-dev
# install the GnuPG PECL package
sudo pecl install gnupg
# register the GnuPG PECL package as an available module
sudo sh -c 'echo "extension=gnupg.so" > /etc/php/7.0/mods-available/gnupg.ini'
# activate the GnuPG PECL package in PHP CLI and PHP-FPM
sudo ln -s /etc/php/7.0/mods-available/gnupg.ini /etc/php/7.0/cli/conf.d/20-gnupg.ini
sudo ln -s /etc/php/7.0/mods-available/gnupg.ini /etc/php/7.0/fpm/conf.d/20-gnupg.ini
# restart PHP-FPM to load the GnuPG PECL package
sudo /etc/init.d/php7.0-fpm restart
```

### Service Setup

Rename the "config.php.default" to "config.php" and set the necessary configuration items.

**Beware:** With version 0.8b0 the structure of the secret sharing links has slightly changed. You have to set the *SUPPORT_LEGACY_LINKS* configuration value to *true* if you want to support secret sharing links that have been generated for older versions of Shared-Secrets. Failure to do so will break these legacy links.

### TLS Recommendation

It is strongly recommended to use TLS to protect the connection between the server and the clients.
Expand All @@ -149,15 +118,14 @@ It is strongly recommended to use TLS to protect the connection between the serv
* [Bootstrap](https://getbootstrap.com): for providing an easy-to-use framework to build nice-looking applications
* [buffer](https://github.com/feross/buffer): for providing Base64 encoding and array conversion functions
* [GnuPG](https://www.gnupg.org): for providing a reliable tool for secure communication
* [GnuPG PECL package](https://pecl.php.net/package/gnupg): for providing a clean interface to GnuPG
* [GnuPG PECL package](https://pecl.php.net/package/gnupg): for providing a clean interface to GnuPG (*currently not supported*)
* [html5shiv](https://github.com/aFarkas/html5shiv): for handling Internet Explorer compatibility stuff
* [jQuery](https://jquery.com): for just existing
* [Katharina Franz](https://www.katharinafranz.com): for suggesting Bootstrap as an easy-to-use framework to build nice-looking applications
* [Respond.js](https://github.com/scottjehl/Respond): for handling even more Internet Explorer compatibility stuff

## ToDo

* make PECL method work in a chroot environment to get rid of the direct call method
* switch to a more personalized design (current design is taken from [here](https://github.com/twbs/bootstrap/tree/master/docs/examples/starter-template))
* implement an alternative encryption scheme based on AES instead of GPG (fewer dependencies)
* implement an expiry date functionality
Expand Down
147 changes: 62 additions & 85 deletions actions/read.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,111 +6,88 @@
function read_secret($secret) {
$result = null;

# only execute the legacy code if it are activated
if (SUPPORT_LEGACY_LINKS) {
$is_legacy_link = (false !== strpos(rtrim($secret, BASE64_MARKER_END), BASE64_MARKER_END));

# handle secret decoding
if ($is_legacy_link) {
$secret = url_base64_decode_legacy($secret);
} else {
$secret = url_base64_decode($secret);
}
} else {
# handle secret decoding
$secret = url_base64_decode($secret);
}

# get the checksum of the URI content
$checksum = hash("sha256", $secret);

if (!empty($checksum)) {
# connect to mysql server
$mysql = mysqli_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB);

if (null === mysqli_connect_error()) {
# prepare the read statement
$select = mysqli_prepare($mysql, MYSQL_READ);

if (false !== $select) {
# set string parameter of read statement to $checksum
if (mysqli_stmt_bind_param($select, "s", $checksum)) {
# execute statement
if (mysqli_stmt_execute($select)) {
# bind result variables
if (mysqli_stmt_bind_result($select, $fingerprint_found)) {
# fetch result variables
if (true === mysqli_stmt_fetch($select)) {
# close select statement to be able to insert later on
mysqli_stmt_close($select);
$select = null;

# only proceed if the fingerprint has not been found
if (0 === $fingerprint_found) {
# only execute the legacy code if it are activated
if (SUPPORT_LEGACY_LINKS) {
# decrypt secret
if ($is_legacy_link) {
$decrypted_secret = decrypt_legacy($secret, GPG_HOME_DIR, GPG_PASSPHRASE_FILE);
} else {
if (GNUPG_PECL) {
$decrypted_secret = decrypt_pecl(base64_decode($secret, true), GPG_KEY_FINGERPRINT, GPG_HOME_DIR, GPG_PASSPHRASE_FILE);
} else {
$decrypted_secret = decrypt(base64_decode($secret, true), GPG_HOME_DIR, GPG_PASSPHRASE_FILE);
}
}
} else {
# handle secret decoding
$secret = url_base64_decode($secret);

# only proceed when the secret is not empty
if (!empty($secret)) {
# get the checksum of the URI content
$checksum = hash("sha256", $secret);

if (!empty($checksum)) {
# connect to mysql server
$mysql = mysqli_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB);

if (null === mysqli_connect_error()) {
# prepare the read statement
$select = mysqli_prepare($mysql, MYSQL_READ);

if (false !== $select) {
# set string parameter of read statement to $checksum
if (mysqli_stmt_bind_param($select, "s", $checksum)) {
# execute statement
if (mysqli_stmt_execute($select)) {
# bind result variables
if (mysqli_stmt_bind_result($select, $fingerprint_found)) {
# fetch result variables
if (true === mysqli_stmt_fetch($select)) {
# close select statement to be able to insert later on
mysqli_stmt_close($select);
$select = null;

# only proceed if the fingerprint has not been found
if (0 === $fingerprint_found) {
# decrypt secret
if (GNUPG_PECL) {
$decrypted_secret = decrypt_pecl(base64_decode($secret, true), GPG_KEY_FINGERPRINT, GPG_HOME_DIR, GPG_PASSPHRASE_FILE);
} else {
$decrypted_secret = decrypt(base64_decode($secret, true), GPG_HOME_DIR, GPG_PASSPHRASE_FILE);
}
}

if (null !== $decrypted_secret) {
# prepare the write statement
$insert = mysqli_prepare($mysql, MYSQL_WRITE);

if (false !== $insert) {
# only set temporarily
$client_ip = CLIENT_IP;

# set string parameter of write statement to $checksum and client IP
if (mysqli_stmt_bind_param($insert, "ss", $checksum, $client_ip)) {
# execute statement
if (mysqli_stmt_execute($insert)) {
# return secret
$result = htmlentities($decrypted_secret);
if (null !== $decrypted_secret) {
# prepare the write statement
$insert = mysqli_prepare($mysql, MYSQL_WRITE);

if (false !== $insert) {
# only set temporarily
$client_ip = CLIENT_IP;

# set string parameter of write statement to $checksum and client IP
if (mysqli_stmt_bind_param($insert, "ss", $checksum, $client_ip)) {
# execute statement
if (mysqli_stmt_execute($insert)) {
# return secret
$result = htmlentities($decrypted_secret);

# close insert statement before proceeding
mysqli_stmt_close($insert);
$insert = null;
}
}

# close insert statement before proceeding
# close insert statement
if (null !== $insert) {
mysqli_stmt_close($insert);
$insert = null;
}
}

# close insert statement
if (null !== $insert) {
mysqli_stmt_close($insert);
}
}
} else {
$result = "<strong>ERROR: SECRET HAS ALREADY BEEN RETRIEVED.</strong>";
}
} else {
$result = "<strong>ERROR: SECRET HAS ALREADY BEEN RETRIEVED.</strong>";
}
}
}
}
}

# close select statement
if (null !== $select) {
mysqli_stmt_close($select);
# close select statement
if (null !== $select) {
mysqli_stmt_close($select);
}
}
}

# close mysql connection
mysqli_close($mysql);
# close mysql connection
mysqli_close($mysql);
}
}
}

Expand Down
9 changes: 2 additions & 7 deletions config.php.default
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,12 @@
# password-protection of secrets on top of the server-side
# encryption, set this configuration value to true to enable
# the optional password-protection
define("ENABLE_PASSWORD_PROTECTION", false);
define("ENABLE_PASSWORD_PROTECTION", true);

# this is the configuration to either enable or disable the
# logging of IP addresses for retrieved secrets, set this
# configuration value to false to disable the logging of
# IP addresses
define("LOG_IP_ADDRESS", true);

# this is the configuration to either enable or disable the
# support for legacy links, set this configuration value to
# true to enable the support for legacy links
define("SUPPORT_LEGACY_LINKS", false);
define("LOG_IP_ADDRESS", false);

?>
4 changes: 2 additions & 2 deletions index.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

# Shared-Secrets v0.10b1
# Shared-Secrets v0.11b0
#
# Copyright (c) 2016, SysEleven GmbH
# All rights reserved.
Expand Down Expand Up @@ -90,7 +90,7 @@
define("SECRET_ACTION", $action);

# check if the GnuPG PECL package is available
define("GNUPG_PECL", (extension_loaded("gnupg") && is_dir(GPG_HOME_DIR)));
define("GNUPG_PECL", (extension_loaded("gnupg") && is_dir(GPG_HOME_DIR) && !defined("DISABLE_GNUPG_PECL")));

# only proceed when a GET or POST request is encountered
if (in_array(REQUEST_METHOD, array("get", "post"))) {
Expand Down
16 changes: 3 additions & 13 deletions libs/shared-secrets.def.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# prevent direct access
if (!defined("SYS11_SECRETS")) { die(""); }

# forcefully disable GnuPG PECL
define("DISABLE_GNUPG_PECL", true);

# define encoding markers
define("BASE64_MARKER_A", "+");
define("BASE64_MARKER_B", "/");
Expand All @@ -29,17 +32,4 @@
# define stream buffer size
define("STREAM_BUFFER", 1024);

# only define the legacy values if they are activated
if (SUPPORT_LEGACY_LINKS) {
# define GPG message parts
define("GPG_MESSAGE_COMMENT", "Comment:");
define("GPG_MESSAGE_COMMENT_DUMMY", "Dummy");
define("GPG_MESSAGE_LINE_LENGTH", 64);
define("GPG_MESSAGE_LINE_SEPARATOR", "\n");
define("GPG_MESSAGE_PARTS_MARKER", "=");
define("GPG_MESSAGE_VALUE_SEPARATOR", " ");
define("GPG_MESSAGE_PREFIX", "-----BEGIN PGP MESSAGE-----");
define("GPG_MESSAGE_SUFFIX", "-----END PGP MESSAGE-----");
}

?>
Loading

0 comments on commit 7da09f5

Please sign in to comment.