Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use OpenSSL for elliptic curve crypto #187

Merged
merged 2 commits into from
Nov 22, 2020
Merged
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
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