Skip to content

Commit

Permalink
Merge pull request FD-#187 from jasLogic/master
Browse files Browse the repository at this point in the history
Use OpenSSL for elliptic curve crypto
  • Loading branch information
pallas authored Nov 22, 2020
2 parents adfa7de + 780981f commit 3c82178
Show file tree
Hide file tree
Showing 29 changed files with 325 additions and 5,981 deletions.
2 changes: 0 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ set (CMAKE_CXX_STANDARD 11)

set (RENDERER_FLAGS "")

add_subdirectory(lib/curve25519)
add_subdirectory(lib/ed25519)
add_subdirectory(lib/playfair)
add_subdirectory(lib/llhttp)
add_subdirectory(lib)
Expand Down
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ The code in this repository accumulated from various sources over time. Here is
* **Juho Vähä-Herttua** and contributors: Created an AirPlay audio server called [ShairPlay](https://github.com/juhovh/shairplay), including support for Fairplay based on PlayFair. Most of the code in `lib/` originally stems from this project. License: GNU LGPLv2.1+
* **EstebanKubata**: Created a FairPlay library called [PlayFair](https://github.com/EstebanKubata/playfair). Located in the `lib/playfair` folder. License: GNU GPL
* **Joyent, Inc and contributors**: Created an http library called [llhttp](https://github.com/nodejs/llhttp). Located at `lib/llhttp/`. License: MIT
* **Google, Inc and contributors**: Created an implementation of curve 25519 called [curve25519-donna](https://github.com/agl/curve25519-donna). Located in the `lib/curve25519` folder. License: 3-Clause BSD
* **Team XBMC**: Managed to show a black background for OpenMAX video rendering. This code is used in the video renderer. License: GNU GPL
* **Orson Peters and contributors**: An implementation of [Ed25519](https://github.com/orlp/ed25519) signatures. Located in `lib/ed25519`, License: ZLIB; Depends on LibTomCrypt, License: Public Domain
* **Alex Izvorski and contributors**: Wrote [h264bitstream](https://github.com/aizvorski/h264bitstream), a library for manipulation h264 streams. Used for reducing delay in the Raspberry Pi video pipeline. Located in the `renderers/h264-bitstream` folder. License: GNU LGPLv2.1


Expand All @@ -149,7 +147,6 @@ Your contributions are more than welcome!

# Todo

* Use OpenSSL for the elliptic curve crypto?
* Bug: Sometimes cannot be stopped?

# Changelog
Expand Down
6 changes: 2 additions & 4 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.4.1)
include_directories( curve25519 ed25519 playfair llhttp )
include_directories( playfair llhttp )

aux_source_directory(. play_src)
set(DIR_SRCS ${play_src})
Expand All @@ -13,14 +13,12 @@ find_library( LIBPLIST NAMES plist plist-2.0 )

target_link_libraries( airplay
pthread
curve25519
ed25519
playfair
llhttp
${LIBPLIST} )

if( UNIX AND NOT APPLE )
find_package(OpenSSL REQUIRED)
find_package(OpenSSL 1.1.1 REQUIRED)
target_link_libraries( airplay OpenSSL::Crypto )
target_link_libraries( airplay dns_sd )
else()
Expand Down
202 changes: 200 additions & 2 deletions lib/crypto.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi
* Copyright (C) 2019 Florian Draschbacher
* Copyright (C) 2020 Jaslo Ziska
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -23,6 +24,7 @@
#include <openssl/err.h>

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

Expand All @@ -41,8 +43,8 @@ uint8_t waste[AES_128_BLOCK_SIZE];
void handle_error(const char* location) {
long error = ERR_get_error();
const char* error_str = ERR_error_string(error, NULL);
printf("Crypto error at %s: %s\n", location, error_str);
assert(false);
fprintf(stderr, "Crypto error at %s: %s\n", location, error_str);
exit(EXIT_FAILURE);
}

aes_ctx_t *aes_init(const uint8_t *key, const uint8_t *iv, const EVP_CIPHER *type, aes_direction_t direction) {
Expand Down Expand Up @@ -163,6 +165,202 @@ void aes_cbc_destroy(aes_ctx_t *ctx) {
aes_destroy(ctx);
}

// X25519

struct x25519_key_s {
EVP_PKEY *pkey;
};

x25519_key_t *x25519_key_generate(void) {
x25519_key_t *key;
EVP_PKEY_CTX *pctx;

key = calloc(1, sizeof(x25519_key_t));
assert(key);

pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
if (!pctx) {
handle_error(__func__);
}
if (!EVP_PKEY_keygen_init(pctx)) {
handle_error(__func__);
}
if (!EVP_PKEY_keygen(pctx, &key->pkey)) {
handle_error(__func__);
}
EVP_PKEY_CTX_free(pctx);

return key;
}

x25519_key_t *x25519_key_from_raw(const unsigned char data[X25519_KEY_SIZE]) {
x25519_key_t *key;

key = malloc(sizeof(x25519_key_t));
assert(key);

key->pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, data, X25519_KEY_SIZE);
if (!key->pkey) {
handle_error(__func__);
}

return key;
}

void x25519_key_get_raw(unsigned char data[X25519_KEY_SIZE], const x25519_key_t *key) {
assert(key);
if (!EVP_PKEY_get_raw_public_key(key->pkey, data, &(size_t) {X25519_KEY_SIZE})) {
handle_error(__func__);
}
}

void x25519_key_destroy(x25519_key_t *key) {
if (key) {
EVP_PKEY_free(key->pkey);
free(key);
}
}

void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_key_t *ours, const x25519_key_t *theirs) {
EVP_PKEY_CTX *pctx;

assert(ours);
assert(theirs);

pctx = EVP_PKEY_CTX_new(ours->pkey, NULL);
if (!pctx) {
handle_error(__func__);
}
if (!EVP_PKEY_derive_init(pctx)) {
handle_error(__func__);
}
if (!EVP_PKEY_derive_set_peer(pctx, theirs->pkey)) {
handle_error(__func__);
}
if (!EVP_PKEY_derive(pctx, secret, &(size_t) {X25519_KEY_SIZE})) {
handle_error(__func__);
}
EVP_PKEY_CTX_free(pctx);
}

// ED25519

struct ed25519_key_s {
EVP_PKEY *pkey;
};

ed25519_key_t *ed25519_key_generate(void) {
ed25519_key_t *key;
EVP_PKEY_CTX *pctx;

key = calloc(1, sizeof(ed25519_key_t));
assert(key);

pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL);
if (!pctx) {
handle_error(__func__);
}
if (!EVP_PKEY_keygen_init(pctx)) {
handle_error(__func__);
}
if (!EVP_PKEY_keygen(pctx, &key->pkey)) {
handle_error(__func__);
}
EVP_PKEY_CTX_free(pctx);

return key;
}

ed25519_key_t *ed25519_key_from_raw(const unsigned char data[ED25519_KEY_SIZE]) {
ed25519_key_t *key;

key = malloc(sizeof(ed25519_key_t));
assert(key);

key->pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, data, ED25519_KEY_SIZE);
if (!key->pkey) {
handle_error(__func__);
}

return key;
}

void ed25519_key_get_raw(unsigned char data[ED25519_KEY_SIZE], const ed25519_key_t *key) {
assert(key);
if (!EVP_PKEY_get_raw_public_key(key->pkey, data, &(size_t) {ED25519_KEY_SIZE})) {
handle_error(__func__);
}
}

ed25519_key_t *ed25519_key_copy(const ed25519_key_t *key) {
ed25519_key_t *new_key;

assert(key);

new_key = malloc(sizeof(ed25519_key_t));
assert(new_key);

new_key->pkey = key->pkey;
if (!EVP_PKEY_up_ref(key->pkey)) {
handle_error(__func__);
}

return new_key;
}

void ed25519_sign(unsigned char *signature, size_t signature_len,
const unsigned char *data, size_t data_len,
const ed25519_key_t *key)
{
EVP_MD_CTX *mctx;

mctx = EVP_MD_CTX_new();
if (!mctx) {
handle_error(__func__);
}

if (!EVP_DigestSignInit(mctx, NULL, NULL, NULL, key->pkey)) {
handle_error(__func__);
}
if (!EVP_DigestSign(mctx, signature, &signature_len, data, data_len)) {
handle_error(__func__);
}

EVP_MD_CTX_free(mctx);
}

int ed25519_verify(const unsigned char *signature, size_t signature_len,
const unsigned char *data, size_t data_len,
const ed25519_key_t *key)
{
EVP_MD_CTX *mctx;

mctx = EVP_MD_CTX_new();
if (!mctx) {
handle_error(__func__);
}

if (!EVP_DigestVerifyInit(mctx, NULL, NULL, NULL, key->pkey)) {
handle_error(__func__);
}

int ret = EVP_DigestVerify(mctx, signature, signature_len, data, data_len);
if (ret < 0) {
handle_error(__func__);
}

EVP_MD_CTX_free(mctx);

return ret;
}

void ed25519_key_destroy(ed25519_key_t *key) {
if (key) {
EVP_PKEY_free(key->pkey);
free(key);
}
}

// SHA 512

struct sha_ctx_s {
Expand Down
40 changes: 39 additions & 1 deletion lib/crypto.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi
* Copyright (C) 2019 Florian Draschbacher
* Copyright (C) 2020 Jaslo Ziska
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -17,14 +18,15 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

/*
/*
* Helper methods for various crypto operations.
* Uses OpenSSL behind the scenes.
*/

#ifndef CRYPTO_H
#define CRYPTO_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -52,6 +54,42 @@ void aes_cbc_encrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len);
void aes_cbc_decrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len);
void aes_cbc_destroy(aes_ctx_t *ctx);

// X25519

#define X25519_KEY_SIZE 32

typedef struct x25519_key_s x25519_key_t;

x25519_key_t *x25519_key_generate(void);
x25519_key_t *x25519_key_from_raw(const unsigned char data[X25519_KEY_SIZE]);
void x25519_key_get_raw(unsigned char data[X25519_KEY_SIZE], const x25519_key_t *key);
void x25519_key_destroy(x25519_key_t *key);

void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_key_t *ours, const x25519_key_t *theirs);

// ED25519

#define ED25519_KEY_SIZE 32

typedef struct ed25519_key_s ed25519_key_t;

ed25519_key_t *ed25519_key_generate(void);
ed25519_key_t *ed25519_key_from_raw(const unsigned char data[ED25519_KEY_SIZE]);
void ed25519_key_get_raw(unsigned char data[ED25519_KEY_SIZE], const ed25519_key_t *key);
/*
* Note that this function does *not copy* the OpenSSL key but only the wrapper. The internal OpenSSL key is still the
* same. Only the reference count is increased so destroying both the original and the copy is allowed.
*/
ed25519_key_t *ed25519_key_copy(const ed25519_key_t *key);
void ed25519_key_destroy(ed25519_key_t *key);

void ed25519_sign(unsigned char *signature, size_t signature_len,
const unsigned char *data, size_t data_len,
const ed25519_key_t *key);
int ed25519_verify(const unsigned char *signature, size_t signature_len,
const unsigned char *data, size_t data_len,
const ed25519_key_t *key);

// SHA512

typedef struct sha_ctx_s sha_ctx_t;
Expand Down
6 changes: 0 additions & 6 deletions lib/curve25519/CMakeLists.txt

This file was deleted.

Loading

0 comments on commit 3c82178

Please sign in to comment.