Bring contents of lib up to date with current FD-:master RPiPlay

the plist library is removed (the Linux distributions version will be used)
(libplist 2.0)

the library llhttp v 6.0.2 is added to replace http_parser

The curve25519 and ed25519 libraries are removed, and replaced with their
OpenSSL 1.1.1 implementations

crypto is updated
This commit is contained in:
fduncanh
2021-07-31 19:29:58 -04:00
parent 6a473d6026
commit 623b638357
67 changed files with 16498 additions and 15862 deletions

View File

@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.4.1)
include_directories( curve25519 ed25519 playfair plist/plist )
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -march=native -DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -Wall -g")
include_directories( playfair llhttp )
aux_source_directory(. play_src)
set(DIR_SRCS ${play_src})
@@ -11,14 +9,21 @@ add_library( airplay
${DIR_SRCS}
)
target_link_libraries( airplay
pthread
curve25519
ed25519
playfair
plist )
find_library( LIBPLIST NAMES plist plist-2.0 )
find_package(OpenSSL REQUIRED)
target_link_libraries( airplay
pthread
playfair
llhttp
${LIBPLIST} )
if( UNIX AND NOT APPLE )
find_package(OpenSSL 1.1.1 REQUIRED)
target_compile_definitions(airplay PUBLIC OPENSSL_API_COMPAT=0x10101000L)
target_link_libraries( airplay OpenSSL::Crypto )
target_link_libraries( airplay dns_sd )
else()
include_directories( /usr/local/opt/openssl@1.1/include/ )
target_link_libraries( airplay /usr/local/opt/openssl@1.1/lib/libcrypto.a )
endif()

View File

@@ -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
@@ -23,6 +24,7 @@
#include <openssl/err.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
@@ -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) {
@@ -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 {

View File

@@ -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
@@ -17,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
/*
* Helper methods for various crypto operations.
* Uses OpenSSL behind the scenes.
*/
@@ -25,6 +26,7 @@
#ifndef CRYPTO_H
#define CRYPTO_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
@@ -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;

View File

@@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. curve25519_src)
set(DIR_SRCS ${curve25519_src})
add_library( curve25519
STATIC
${DIR_SRCS})

View File

@@ -1,860 +0,0 @@
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* More information about curve25519 can be found here
* http://cr.yp.to/ecdh.html
*
* djb's sample implementation of curve25519 is written in a special assembly
* language called qhasm and uses the floating point registers.
*
* This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation. */
#include <string.h>
#include <stdint.h>
#ifdef _MSC_VER
#define inline __inline
#endif
typedef uint8_t u8;
typedef int32_t s32;
typedef int64_t limb;
/* Field element representation:
*
* Field elements are written as an array of signed, 64-bit limbs, least
* significant first. The value of the field element is:
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
*
* i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
/* Sum two numbers: output += in */
static void fsum(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; i += 2) {
output[0+i] = output[0+i] + in[0+i];
output[1+i] = output[1+i] + in[1+i];
}
}
/* Find the difference of two numbers: output = in - output
* (note the order of the arguments!). */
static void fdifference(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] - output[i];
}
}
/* Multiply a number by a scalar: output = in * scalar */
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] * scalar;
}
}
/* Multiply two numbers: output = in2 * in
*
* output must be distinct to both inputs. The inputs are reduced coefficient
* form, the output is not.
*
* output[x] <= 14 * the largest product of the input limbs. */
static void fproduct(limb *output, const limb *in2, const limb *in) {
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
((limb) ((s32) in2[1])) * ((s32) in[0]);
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[2]) +
((limb) ((s32) in2[2])) * ((s32) in[0]);
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
((limb) ((s32) in2[2])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[0]);
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[1])) +
((limb) ((s32) in2[0])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[0]);
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[0]);
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[1])) +
((limb) ((s32) in2[2])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[2]) +
((limb) ((s32) in2[0])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[0]);
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[0]);
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[1])) +
((limb) ((s32) in2[2])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[2]) +
((limb) ((s32) in2[0])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[0]);
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[4]) +
((limb) ((s32) in2[3])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[0]);
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
((limb) ((s32) in2[3])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[1])) +
((limb) ((s32) in2[4])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[4]) +
((limb) ((s32) in2[2])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[2]);
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[5]) +
((limb) ((s32) in2[4])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[4]) +
((limb) ((s32) in2[3])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[2]);
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[5]) +
((limb) ((s32) in2[3])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[3])) +
((limb) ((s32) in2[4])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[4]);
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[6]) +
((limb) ((s32) in2[5])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[5]) +
((limb) ((s32) in2[4])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[4]);
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
((limb) ((s32) in2[5])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[5])) +
((limb) ((s32) in2[6])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[6]);
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[7]) +
((limb) ((s32) in2[6])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[6]);
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[7]));
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[8]);
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
}
/* Reduce a long form to a short form by taking the input mod 2^255 - 19.
*
* On entry: |output[i]| < 14*2^54
* On exit: |output[0..8]| < 280*2^54 */
static void freduce_degree(limb *output) {
/* Each of these shifts and adds ends up multiplying the value by 19.
*
* For output[0..8], the absolute entry value is < 14*2^54 and we add, at
* most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
output[8] += output[18] << 4;
output[8] += output[18] << 1;
output[8] += output[18];
output[7] += output[17] << 4;
output[7] += output[17] << 1;
output[7] += output[17];
output[6] += output[16] << 4;
output[6] += output[16] << 1;
output[6] += output[16];
output[5] += output[15] << 4;
output[5] += output[15] << 1;
output[5] += output[15];
output[4] += output[14] << 4;
output[4] += output[14] << 1;
output[4] += output[14];
output[3] += output[13] << 4;
output[3] += output[13] << 1;
output[3] += output[13];
output[2] += output[12] << 4;
output[2] += output[12] << 1;
output[2] += output[12];
output[1] += output[11] << 4;
output[1] += output[11] << 1;
output[1] += output[11];
output[0] += output[10] << 4;
output[0] += output[10] << 1;
output[0] += output[10];
}
#if (-1 & 3) != 3
#error "This code only works on a two's complement system"
#endif
/* return v / 2^26, using only shifts and adds.
*
* On entry: v can take any value. */
static inline limb
div_by_2_26(const limb v)
{
/* High word of v; no shift needed. */
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31;
/* Set to 0x3ffffff if v was negative; else set to 0. */
const int32_t roundoff = ((uint32_t) sign) >> 6;
/* Should return v / (1<<26) */
return (v + roundoff) >> 26;
}
/* return v / (2^25), using only shifts and adds.
*
* On entry: v can take any value. */
static inline limb
div_by_2_25(const limb v)
{
/* High word of v; no shift needed*/
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31;
/* Set to 0x1ffffff if v was negative; else set to 0. */
const int32_t roundoff = ((uint32_t) sign) >> 7;
/* Should return v / (1<<25) */
return (v + roundoff) >> 25;
}
/* Reduce all coefficients of the short form input so that |x| < 2^26.
*
* On entry: |output[i]| < 280*2^54 */
static void freduce_coefficients(limb *output) {
unsigned i;
output[10] = 0;
for (i = 0; i < 10; i += 2) {
limb over = div_by_2_26(output[i]);
/* The entry condition (that |output[i]| < 280*2^54) means that over is, at
* most, 280*2^28 in the first iteration of this loop. This is added to the
* next limb and we can approximate the resulting bound of that limb by
* 281*2^54. */
output[i] -= over << 26;
output[i+1] += over;
/* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
* 281*2^29. When this is added to the next limb, the resulting bound can
* be approximated as 281*2^54.
*
* For subsequent iterations of the loop, 281*2^54 remains a conservative
* bound and no overflow occurs. */
over = div_by_2_25(output[i+1]);
output[i+1] -= over << 25;
output[i+2] += over;
}
/* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
output[0] += output[10] << 4;
output[0] += output[10] << 1;
output[0] += output[10];
output[10] = 0;
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
* So |over| will be no more than 2^16. */
{
limb over = div_by_2_26(output[0]);
output[0] -= over << 26;
output[1] += over;
}
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
* bound on |output[1]| is sufficient to meet our needs. */
}
/* A helpful wrapper around fproduct: output = in * in2.
*
* On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
*
* output must be distinct to both inputs. The output is reduced degree
* (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
static void
fmul(limb *output, const limb *in, const limb *in2) {
limb t[19];
fproduct(t, in, in2);
/* |t[i]| < 14*2^54 */
freduce_degree(t);
freduce_coefficients(t);
/* |t[i]| < 2^26 */
memcpy(output, t, sizeof(limb) * 10);
}
/* Square a number: output = in**2
*
* output must be distinct from the input. The inputs are reduced coefficient
* form, the output is not.
*
* output[x] <= 14 * the largest product of the input limbs. */
static void fsquare_inner(limb *output, const limb *in) {
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
((limb) ((s32) in[0])) * ((s32) in[2]));
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
((limb) ((s32) in[0])) * ((s32) in[3]));
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
((limb) ((s32) in[1])) * ((s32) in[4]) +
((limb) ((s32) in[0])) * ((s32) in[5]));
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
((limb) ((s32) in[2])) * ((s32) in[4]) +
((limb) ((s32) in[0])) * ((s32) in[6]) +
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
((limb) ((s32) in[2])) * ((s32) in[5]) +
((limb) ((s32) in[1])) * ((s32) in[6]) +
((limb) ((s32) in[0])) * ((s32) in[7]));
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
((limb) ((s32) in[0])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[5])));
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
((limb) ((s32) in[3])) * ((s32) in[6]) +
((limb) ((s32) in[2])) * ((s32) in[7]) +
((limb) ((s32) in[1])) * ((s32) in[8]) +
((limb) ((s32) in[0])) * ((s32) in[9]));
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
((limb) ((s32) in[4])) * ((s32) in[6]) +
((limb) ((s32) in[2])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
((limb) ((s32) in[1])) * ((s32) in[9])));
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
((limb) ((s32) in[4])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[8]) +
((limb) ((s32) in[2])) * ((s32) in[9]));
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[9])));
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
((limb) ((s32) in[5])) * ((s32) in[8]) +
((limb) ((s32) in[4])) * ((s32) in[9]));
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
((limb) ((s32) in[6])) * ((s32) in[8]) +
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
((limb) ((s32) in[6])) * ((s32) in[9]));
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
}
/* fsquare sets output = in^2.
*
* On entry: The |in| argument is in reduced coefficients form and |in[i]| <
* 2^27.
*
* On exit: The |output| argument is in reduced coefficients form (indeed, one
* need only provide storage for 10 limbs) and |out[i]| < 2^26. */
static void
fsquare(limb *output, const limb *in) {
limb t[19];
fsquare_inner(t, in);
/* |t[i]| < 14*2^54 because the largest product of two limbs will be <
* 2^(27+27) and fsquare_inner adds together, at most, 14 of those
* products. */
freduce_degree(t);
freduce_coefficients(t);
/* |t[i]| < 2^26 */
memcpy(output, t, sizeof(limb) * 10);
}
/* Take a little-endian, 32-byte number and expand it into polynomial form */
static void
fexpand(limb *output, const u8 *input) {
#define F(n,start,shift,mask) \
output[n] = ((((limb) input[start + 0]) | \
((limb) input[start + 1]) << 8 | \
((limb) input[start + 2]) << 16 | \
((limb) input[start + 3]) << 24) >> shift) & mask;
F(0, 0, 0, 0x3ffffff);
F(1, 3, 2, 0x1ffffff);
F(2, 6, 3, 0x3ffffff);
F(3, 9, 5, 0x1ffffff);
F(4, 12, 6, 0x3ffffff);
F(5, 16, 0, 0x1ffffff);
F(6, 19, 1, 0x3ffffff);
F(7, 22, 3, 0x1ffffff);
F(8, 25, 4, 0x3ffffff);
F(9, 28, 6, 0x1ffffff);
#undef F
}
#if (-32 >> 1) != -16
#error "This code only works when >> does sign-extension on negative numbers"
#endif
/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
static s32 s32_eq(s32 a, s32 b) {
a = ~(a ^ b);
a &= a << 16;
a &= a << 8;
a &= a << 4;
a &= a << 2;
a &= a << 1;
return a >> 31;
}
/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
* both non-negative. */
static s32 s32_gte(s32 a, s32 b) {
a -= b;
/* a >= 0 iff a >= b. */
return ~(a >> 31);
}
/* Take a fully reduced polynomial form number and contract it into a
* little-endian, 32-byte array.
*
* On entry: |input_limbs[i]| < 2^26 */
static void
fcontract(u8 *output, limb *input_limbs) {
int i;
int j;
s32 input[10];
s32 mask;
/* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
for (i = 0; i < 10; i++) {
input[i] = input_limbs[i];
}
for (j = 0; j < 2; ++j) {
for (i = 0; i < 9; ++i) {
if ((i & 1) == 1) {
/* This calculation is a time-invariant way to make input[i]
* non-negative by borrowing from the next-larger limb. */
const s32 mask = input[i] >> 31;
const s32 carry = -((input[i] & mask) >> 25);
input[i] = input[i] + (carry << 25);
input[i+1] = input[i+1] - carry;
} else {
const s32 mask = input[i] >> 31;
const s32 carry = -((input[i] & mask) >> 26);
input[i] = input[i] + (carry << 26);
input[i+1] = input[i+1] - carry;
}
}
/* There's no greater limb for input[9] to borrow from, but we can multiply
* by 19 and borrow from input[0], which is valid mod 2^255-19. */
{
const s32 mask = input[9] >> 31;
const s32 carry = -((input[9] & mask) >> 25);
input[9] = input[9] + (carry << 25);
input[0] = input[0] - (carry * 19);
}
/* After the first iteration, input[1..9] are non-negative and fit within
* 25 or 26 bits, depending on position. However, input[0] may be
* negative. */
}
/* The first borrow-propagation pass above ended with every limb
except (possibly) input[0] non-negative.
If input[0] was negative after the first pass, then it was because of a
carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
In the second pass, each limb is decreased by at most one. Thus the second
borrow-propagation pass could only have wrapped around to decrease
input[0] again if the first pass left input[0] negative *and* input[1]
through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
and this last borrow-propagation step will leave input[1] non-negative. */
{
const s32 mask = input[0] >> 31;
const s32 carry = -((input[0] & mask) >> 26);
input[0] = input[0] + (carry << 26);
input[1] = input[1] - carry;
}
/* All input[i] are now non-negative. However, there might be values between
* 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
for (j = 0; j < 2; j++) {
for (i = 0; i < 9; i++) {
if ((i & 1) == 1) {
const s32 carry = input[i] >> 25;
input[i] &= 0x1ffffff;
input[i+1] += carry;
} else {
const s32 carry = input[i] >> 26;
input[i] &= 0x3ffffff;
input[i+1] += carry;
}
}
{
const s32 carry = input[9] >> 25;
input[9] &= 0x1ffffff;
input[0] += 19*carry;
}
}
/* If the first carry-chain pass, just above, ended up with a carry from
* input[9], and that caused input[0] to be out-of-bounds, then input[0] was
* < 2^26 + 2*19, because the carry was, at most, two.
*
* If the second pass carried from input[9] again then input[0] is < 2*19 and
* the input[9] -> input[0] carry didn't push input[0] out of bounds. */
/* It still remains the case that input might be between 2^255-19 and 2^255.
* In this case, input[1..9] must take their maximum value and input[0] must
* be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
mask = s32_gte(input[0], 0x3ffffed);
for (i = 1; i < 10; i++) {
if ((i & 1) == 1) {
mask &= s32_eq(input[i], 0x1ffffff);
} else {
mask &= s32_eq(input[i], 0x3ffffff);
}
}
/* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
* this conditionally subtracts 2^255-19. */
input[0] -= mask & 0x3ffffed;
for (i = 1; i < 10; i++) {
if ((i & 1) == 1) {
input[i] -= mask & 0x1ffffff;
} else {
input[i] -= mask & 0x3ffffff;
}
}
input[1] <<= 2;
input[2] <<= 3;
input[3] <<= 5;
input[4] <<= 6;
input[6] <<= 1;
input[7] <<= 3;
input[8] <<= 4;
input[9] <<= 6;
#define F(i, s) \
output[s+0] |= input[i] & 0xff; \
output[s+1] = (input[i] >> 8) & 0xff; \
output[s+2] = (input[i] >> 16) & 0xff; \
output[s+3] = (input[i] >> 24) & 0xff;
output[0] = 0;
output[16] = 0;
F(0,0);
F(1,3);
F(2,6);
F(3,9);
F(4,12);
F(5,16);
F(6,19);
F(7,22);
F(8,25);
F(9,28);
#undef F
}
/* Input: Q, Q', Q-Q'
* Output: 2Q, Q+Q'
*
* x2 z3: long form
* x3 z3: long form
* x z: short form, destroyed
* xprime zprime: short form, destroyed
* qmqp: short form, preserved
*
* On entry and exit, the absolute value of the limbs of all inputs and outputs
* are < 2^26. */
static void fmonty(limb *x2, limb *z2, /* output 2Q */
limb *x3, limb *z3, /* output Q + Q' */
limb *x, limb *z, /* input Q */
limb *xprime, limb *zprime, /* input Q' */
const limb *qmqp /* input Q - Q' */) {
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
zzprime[19], zzzprime[19], xxxprime[19];
memcpy(origx, x, 10 * sizeof(limb));
fsum(x, z);
/* |x[i]| < 2^27 */
fdifference(z, origx); /* does x - z */
/* |z[i]| < 2^27 */
memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime);
/* |xprime[i]| < 2^27 */
fdifference(zprime, origxprime);
/* |zprime[i]| < 2^27 */
fproduct(xxprime, xprime, z);
/* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
* 2^(27+27) and fproduct adds together, at most, 14 of those products.
* (Approximating that to 2^58 doesn't work out.) */
fproduct(zzprime, x, zprime);
/* |zzprime[i]| < 14*2^54 */
freduce_degree(xxprime);
freduce_coefficients(xxprime);
/* |xxprime[i]| < 2^26 */
freduce_degree(zzprime);
freduce_coefficients(zzprime);
/* |zzprime[i]| < 2^26 */
memcpy(origxprime, xxprime, sizeof(limb) * 10);
fsum(xxprime, zzprime);
/* |xxprime[i]| < 2^27 */
fdifference(zzprime, origxprime);
/* |zzprime[i]| < 2^27 */
fsquare(xxxprime, xxprime);
/* |xxxprime[i]| < 2^26 */
fsquare(zzzprime, zzprime);
/* |zzzprime[i]| < 2^26 */
fproduct(zzprime, zzzprime, qmqp);
/* |zzprime[i]| < 14*2^52 */
freduce_degree(zzprime);
freduce_coefficients(zzprime);
/* |zzprime[i]| < 2^26 */
memcpy(x3, xxxprime, sizeof(limb) * 10);
memcpy(z3, zzprime, sizeof(limb) * 10);
fsquare(xx, x);
/* |xx[i]| < 2^26 */
fsquare(zz, z);
/* |zz[i]| < 2^26 */
fproduct(x2, xx, zz);
/* |x2[i]| < 14*2^52 */
freduce_degree(x2);
freduce_coefficients(x2);
/* |x2[i]| < 2^26 */
fdifference(zz, xx); // does zz = xx - zz
/* |zz[i]| < 2^27 */
memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665);
/* |zzz[i]| < 2^(27+17) */
/* No need to call freduce_degree here:
fscalar_product doesn't increase the degree of its input. */
freduce_coefficients(zzz);
/* |zzz[i]| < 2^26 */
fsum(zzz, xx);
/* |zzz[i]| < 2^27 */
fproduct(z2, zz, zzz);
/* |z2[i]| < 14*2^(26+27) */
freduce_degree(z2);
freduce_coefficients(z2);
/* |z2|i| < 2^26 */
}
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
* them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
* side-channel attacks.
*
* NOTE that this function requires that 'iswap' be 1 or 0; other values give
* wrong results. Also, the two limb arrays must be in reduced-coefficient,
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
* and all all values in a[0..9],b[0..9] must have magnitude less than
* INT32_MAX. */
static void
swap_conditional(limb a[19], limb b[19], limb iswap) {
unsigned i;
const s32 swap = (s32) -iswap;
for (i = 0; i < 10; ++i) {
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
a[i] = ((s32)a[i]) ^ x;
b[i] = ((s32)b[i]) ^ x;
}
}
/* Calculates nQ where Q is the x-coordinate of a point on the curve
*
* resultx/resultz: the x coordinate of the resulting curve point (short form)
* n: a little endian, 32-byte number
* q: a point of the curve (short form) */
static void
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
unsigned i, j;
memcpy(nqpqx, q, sizeof(limb) * 10);
for (i = 0; i < 32; ++i) {
u8 byte = n[31 - i];
for (j = 0; j < 8; ++j) {
const limb bit = byte >> 7;
swap_conditional(nqx, nqpqx, bit);
swap_conditional(nqz, nqpqz, bit);
fmonty(nqx2, nqz2,
nqpqx2, nqpqz2,
nqx, nqz,
nqpqx, nqpqz,
q);
swap_conditional(nqx2, nqpqx2, bit);
swap_conditional(nqz2, nqpqz2, bit);
t = nqx;
nqx = nqx2;
nqx2 = t;
t = nqz;
nqz = nqz2;
nqz2 = t;
t = nqpqx;
nqpqx = nqpqx2;
nqpqx2 = t;
t = nqpqz;
nqpqz = nqpqz2;
nqpqz2 = t;
byte <<= 1;
}
}
memcpy(resultx, nqx, sizeof(limb) * 10);
memcpy(resultz, nqz, sizeof(limb) * 10);
}
// -----------------------------------------------------------------------------
// Shamelessly copied from djb's code
// -----------------------------------------------------------------------------
static void
crecip(limb *out, const limb *z) {
limb z2[10];
limb z9[10];
limb z11[10];
limb z2_5_0[10];
limb z2_10_0[10];
limb z2_20_0[10];
limb z2_50_0[10];
limb z2_100_0[10];
limb t0[10];
limb t1[10];
int i;
/* 2 */ fsquare(z2,z);
/* 4 */ fsquare(t1,z2);
/* 8 */ fsquare(t0,t1);
/* 9 */ fmul(z9,t0,z);
/* 11 */ fmul(z11,z9,z2);
/* 22 */ fsquare(t0,z11);
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
/* 2^7 - 2^2 */ fsquare(t1,t0);
/* 2^8 - 2^3 */ fsquare(t0,t1);
/* 2^9 - 2^4 */ fsquare(t1,t0);
/* 2^10 - 2^5 */ fsquare(t0,t1);
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
/* 2^12 - 2^2 */ fsquare(t1,t0);
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
/* 2^22 - 2^2 */ fsquare(t1,t0);
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
/* 2^41 - 2^1 */ fsquare(t1,t0);
/* 2^42 - 2^2 */ fsquare(t0,t1);
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
/* 2^52 - 2^2 */ fsquare(t1,t0);
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
/* 2^102 - 2^2 */ fsquare(t0,t1);
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
/* 2^201 - 2^1 */ fsquare(t0,t1);
/* 2^202 - 2^2 */ fsquare(t1,t0);
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
/* 2^251 - 2^1 */ fsquare(t1,t0);
/* 2^252 - 2^2 */ fsquare(t0,t1);
/* 2^253 - 2^3 */ fsquare(t1,t0);
/* 2^254 - 2^4 */ fsquare(t0,t1);
/* 2^255 - 2^5 */ fsquare(t1,t0);
/* 2^255 - 21 */ fmul(out,t1,z11);
}
int
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
limb bp[10], x[10], z[11], zmone[10];
uint8_t e[32];
int i;
for (i = 0; i < 32; ++i) e[i] = secret[i];
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
fexpand(bp, basepoint);
cmult(x, z, e, bp);
crecip(zmone, z);
fmul(z, x, zmone);
fcontract(mypublic, z);
return 0;
}

View File

@@ -1,8 +0,0 @@
#ifndef CURVE25519_DONNA_H
#define CURVE25519_DONNA_H
static const unsigned char kCurve25519BasePoint[32] = { 9 };
int curve25519_donna(unsigned char *mypublic, const unsigned char *secret, const unsigned char *basepoint);
#endif

View File

@@ -215,7 +215,7 @@ dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len,
#endif
dnssd->name_len = name_len;
dnssd->name = calloc(1, name_len);
dnssd->name = calloc(1, name_len + 1);
if (!dnssd->name) {
free(dnssd);
if (error) *error = DNSSD_ERROR_OUTOFMEM;

View File

@@ -6,7 +6,7 @@
#define RAOP_CN "0,1,2,3" /* Audio codec: PCM, ALAC, AAC, AAC ELD */
#define RAOP_ET "0,3,5" /* Encryption type: None, FairPlay, FairPlay SAPv2.5 */
#define RAOP_VV "2"
#define RAOP_FT "0x5A7FFFE6"
#define RAOP_FT "0x5A7FFEE6"
#define RAOP_RHD "5.6.0.0"
#define RAOP_SF "0x4"
#define RAOP_SV "false"
@@ -19,7 +19,7 @@
#define RAOP_VN "65537"
#define RAOP_PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7"
#define AIRPLAY_FEATURES "0x5A7FFFE6"
#define AIRPLAY_FEATURES "0x5A7FFEE6"
#define AIRPLAY_SRCVERS "220.68"
#define AIRPLAY_FLAGS "0x4"
#define AIRPLAY_VV "2"

View File

@@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. ed25519_src)
set(DIR_SRCS ${ed25519_src})
add_library( ed25519
STATIC
${DIR_SRCS})

View File

@@ -1,69 +0,0 @@
#include "ed25519.h"
#include "ge.h"
#include "sc.h"
#include "sha512.h"
/* see http://crypto.stackexchange.com/a/6215/4697 */
void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
unsigned char n[32];
ge_p3 nB;
ge_p1p1 A_p1p1;
ge_p3 A;
ge_p3 public_key_unpacked;
ge_cached T;
sha512_context hash;
unsigned char hashbuf[64];
int i;
/* copy the scalar and clear highest bit */
for (i = 0; i < 31; ++i) {
n[i] = scalar[i];
}
n[31] = scalar[31] & 127;
/* private key: a = n + t */
if (private_key) {
sc_muladd(private_key, SC_1, n, private_key);
// https://github.com/orlp/ed25519/issues/3
sha512_init(&hash);
sha512_update(&hash, private_key + 32, 32);
sha512_update(&hash, scalar, 32);
sha512_final(&hash, hashbuf);
for (i = 0; i < 32; ++i) {
private_key[32 + i] = hashbuf[i];
}
}
/* public key: A = nB + T */
if (public_key) {
/* if we know the private key we don't need a point addition, which is faster */
/* using a "timing attack" you could find out wether or not we know the private
key, but this information seems rather useless - if this is important pass
public_key and private_key seperately in 2 function calls */
if (private_key) {
ge_scalarmult_base(&A, private_key);
} else {
/* unpack public key into T */
ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */
fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */
ge_p3_to_cached(&T, &public_key_unpacked);
/* calculate n*B */
ge_scalarmult_base(&nB, n);
/* A = n*B + T */
ge_add(&A_p1p1, &nB, &T);
ge_p1p1_to_p3(&A, &A_p1p1);
}
/* pack public key */
ge_p3_tobytes(public_key, &A);
}
}

View File

@@ -1,38 +0,0 @@
#ifndef ED25519_H
#define ED25519_H
#include <stddef.h>
#if defined(_WIN32)
#if defined(ED25519_BUILD_DLL)
#define ED25519_DECLSPEC __declspec(dllexport)
#elif defined(ED25519_DLL)
#define ED25519_DECLSPEC __declspec(dllimport)
#else
#define ED25519_DECLSPEC
#endif
#else
#define ED25519_DECLSPEC
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ED25519_NO_SEED
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
#endif
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key);
void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +0,0 @@
#ifndef FE_H
#define FE_H
#include "fixedint.h"
/*
fe means field element.
Here the field is \Z/(2^255-19).
An element t, entries t[0]...t[9], represents the integer
t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
Bounds on each t[i] vary depending on context.
*/
typedef int32_t fe[10];
void fe_0(fe h);
void fe_1(fe h);
void fe_frombytes(fe h, const unsigned char *s);
void fe_tobytes(unsigned char *s, const fe h);
void fe_copy(fe h, const fe f);
int fe_isnegative(const fe f);
int fe_isnonzero(const fe f);
void fe_cmov(fe f, const fe g, unsigned int b);
void fe_cswap(fe f, fe g, unsigned int b);
void fe_neg(fe h, const fe f);
void fe_add(fe h, const fe f, const fe g);
void fe_invert(fe out, const fe z);
void fe_sq(fe h, const fe f);
void fe_sq2(fe h, const fe f);
void fe_mul(fe h, const fe f, const fe g);
void fe_mul121666(fe h, fe f);
void fe_pow22523(fe out, const fe z);
void fe_sub(fe h, const fe f, const fe g);
#endif

View File

@@ -1,72 +0,0 @@
/*
Portable header to provide the 32 and 64 bits type.
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
*/
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
#include <stdint.h>
#define FIXEDINT_H_INCLUDED
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
#include <limits.h>
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
#endif
#endif
#ifndef FIXEDINT_H_INCLUDED
#define FIXEDINT_H_INCLUDED
#include <limits.h>
/* (u)int32_t */
#ifndef uint32_t
#if (ULONG_MAX == 0xffffffffUL)
typedef unsigned long uint32_t;
#elif (UINT_MAX == 0xffffffffUL)
typedef unsigned int uint32_t;
#elif (USHRT_MAX == 0xffffffffUL)
typedef unsigned short uint32_t;
#endif
#endif
#ifndef int32_t
#if (LONG_MAX == 0x7fffffffL)
typedef signed long int32_t;
#elif (INT_MAX == 0x7fffffffL)
typedef signed int int32_t;
#elif (SHRT_MAX == 0x7fffffffL)
typedef signed short int32_t;
#endif
#endif
/* (u)int64_t */
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
typedef long long int64_t;
typedef unsigned long long uint64_t;
#define UINT64_C(v) v ##ULL
#define INT64_C(v) v ##LL
#elif defined(__GNUC__)
__extension__ typedef long long int64_t;
__extension__ typedef unsigned long long uint64_t;
#define UINT64_C(v) v ##ULL
#define INT64_C(v) v ##LL
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
typedef long long int64_t;
typedef unsigned long long uint64_t;
#define UINT64_C(v) v ##ULL
#define INT64_C(v) v ##LL
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define UINT64_C(v) v ##UI64
#define INT64_C(v) v ##I64
#endif
#endif

View File

@@ -1,467 +0,0 @@
#include "ge.h"
#include "precomp_data.h"
/*
r = p + q
*/
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
fe_mul(r->Z, r->X, q->YplusX);
fe_mul(r->Y, r->Y, q->YminusX);
fe_mul(r->T, q->T2d, p->T);
fe_mul(r->X, p->Z, q->Z);
fe_add(t0, r->X, r->X);
fe_sub(r->X, r->Z, r->Y);
fe_add(r->Y, r->Z, r->Y);
fe_add(r->Z, t0, r->T);
fe_sub(r->T, t0, r->T);
}
static void slide(signed char *r, const unsigned char *a) {
int i;
int b;
int k;
for (i = 0; i < 256; ++i) {
r[i] = 1 & (a[i >> 3] >> (i & 7));
}
for (i = 0; i < 256; ++i)
if (r[i]) {
for (b = 1; b <= 6 && i + b < 256; ++b) {
if (r[i + b]) {
if (r[i] + (r[i + b] << b) <= 15) {
r[i] += r[i + b] << b;
r[i + b] = 0;
} else if (r[i] - (r[i + b] << b) >= -15) {
r[i] -= r[i + b] << b;
for (k = i + b; k < 256; ++k) {
if (!r[k]) {
r[k] = 1;
break;
}
r[k] = 0;
}
} else {
break;
}
}
}
}
}
/*
r = a * A + b * B
where a = a[0]+256*a[1]+...+256^31 a[31].
and b = b[0]+256*b[1]+...+256^31 b[31].
B is the Ed25519 base point (x,4/5) with x positive.
*/
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
signed char aslide[256];
signed char bslide[256];
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
ge_p1p1 t;
ge_p3 u;
ge_p3 A2;
int i;
slide(aslide, a);
slide(bslide, b);
ge_p3_to_cached(&Ai[0], A);
ge_p3_dbl(&t, A);
ge_p1p1_to_p3(&A2, &t);
ge_add(&t, &A2, &Ai[0]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[1], &u);
ge_add(&t, &A2, &Ai[1]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[2], &u);
ge_add(&t, &A2, &Ai[2]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[3], &u);
ge_add(&t, &A2, &Ai[3]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[4], &u);
ge_add(&t, &A2, &Ai[4]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[5], &u);
ge_add(&t, &A2, &Ai[5]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[6], &u);
ge_add(&t, &A2, &Ai[6]);
ge_p1p1_to_p3(&u, &t);
ge_p3_to_cached(&Ai[7], &u);
ge_p2_0(r);
for (i = 255; i >= 0; --i) {
if (aslide[i] || bslide[i]) {
break;
}
}
for (; i >= 0; --i) {
ge_p2_dbl(&t, r);
if (aslide[i] > 0) {
ge_p1p1_to_p3(&u, &t);
ge_add(&t, &u, &Ai[aslide[i] / 2]);
} else if (aslide[i] < 0) {
ge_p1p1_to_p3(&u, &t);
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
}
if (bslide[i] > 0) {
ge_p1p1_to_p3(&u, &t);
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
} else if (bslide[i] < 0) {
ge_p1p1_to_p3(&u, &t);
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
}
ge_p1p1_to_p2(r, &t);
}
}
static const fe d = {
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
};
static const fe sqrtm1 = {
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
};
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
fe u;
fe v;
fe v3;
fe vxx;
fe check;
fe_frombytes(h->Y, s);
fe_1(h->Z);
fe_sq(u, h->Y);
fe_mul(v, u, d);
fe_sub(u, u, h->Z); /* u = y^2-1 */
fe_add(v, v, h->Z); /* v = dy^2+1 */
fe_sq(v3, v);
fe_mul(v3, v3, v); /* v3 = v^3 */
fe_sq(h->X, v3);
fe_mul(h->X, h->X, v);
fe_mul(h->X, h->X, u); /* x = uv^7 */
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
fe_mul(h->X, h->X, v3);
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
fe_sq(vxx, h->X);
fe_mul(vxx, vxx, v);
fe_sub(check, vxx, u); /* vx^2-u */
if (fe_isnonzero(check)) {
fe_add(check, vxx, u); /* vx^2+u */
if (fe_isnonzero(check)) {
return -1;
}
fe_mul(h->X, h->X, sqrtm1);
}
if (fe_isnegative(h->X) == (s[31] >> 7)) {
fe_neg(h->X, h->X);
}
fe_mul(h->T, h->X, h->Y);
return 0;
}
/*
r = p + q
*/
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
fe_mul(r->Z, r->X, q->yplusx);
fe_mul(r->Y, r->Y, q->yminusx);
fe_mul(r->T, q->xy2d, p->T);
fe_add(t0, p->Z, p->Z);
fe_sub(r->X, r->Z, r->Y);
fe_add(r->Y, r->Z, r->Y);
fe_add(r->Z, t0, r->T);
fe_sub(r->T, t0, r->T);
}
/*
r = p - q
*/
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
fe_mul(r->Z, r->X, q->yminusx);
fe_mul(r->Y, r->Y, q->yplusx);
fe_mul(r->T, q->xy2d, p->T);
fe_add(t0, p->Z, p->Z);
fe_sub(r->X, r->Z, r->Y);
fe_add(r->Y, r->Z, r->Y);
fe_sub(r->Z, t0, r->T);
fe_add(r->T, t0, r->T);
}
/*
r = p
*/
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
fe_mul(r->X, p->X, p->T);
fe_mul(r->Y, p->Y, p->Z);
fe_mul(r->Z, p->Z, p->T);
}
/*
r = p
*/
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
fe_mul(r->X, p->X, p->T);
fe_mul(r->Y, p->Y, p->Z);
fe_mul(r->Z, p->Z, p->T);
fe_mul(r->T, p->X, p->Y);
}
void ge_p2_0(ge_p2 *h) {
fe_0(h->X);
fe_1(h->Y);
fe_1(h->Z);
}
/*
r = 2 * p
*/
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
fe t0;
fe_sq(r->X, p->X);
fe_sq(r->Z, p->Y);
fe_sq2(r->T, p->Z);
fe_add(r->Y, p->X, p->Y);
fe_sq(t0, r->Y);
fe_add(r->Y, r->Z, r->X);
fe_sub(r->Z, r->Z, r->X);
fe_sub(r->X, t0, r->Y);
fe_sub(r->T, r->T, r->Z);
}
void ge_p3_0(ge_p3 *h) {
fe_0(h->X);
fe_1(h->Y);
fe_1(h->Z);
fe_0(h->T);
}
/*
r = 2 * p
*/
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
ge_p2 q;
ge_p3_to_p2(&q, p);
ge_p2_dbl(r, &q);
}
/*
r = p
*/
static const fe d2 = {
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
};
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
fe_add(r->YplusX, p->Y, p->X);
fe_sub(r->YminusX, p->Y, p->X);
fe_copy(r->Z, p->Z);
fe_mul(r->T2d, p->T, d2);
}
/*
r = p
*/
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
fe_copy(r->X, p->X);
fe_copy(r->Y, p->Y);
fe_copy(r->Z, p->Z);
}
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
fe recip;
fe x;
fe y;
fe_invert(recip, h->Z);
fe_mul(x, h->X, recip);
fe_mul(y, h->Y, recip);
fe_tobytes(s, y);
s[31] ^= fe_isnegative(x) << 7;
}
static unsigned char equal(signed char b, signed char c) {
unsigned char ub = b;
unsigned char uc = c;
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
uint64_t y = x; /* 0: yes; 1..255: no */
y -= 1; /* large: yes; 0..254: no */
y >>= 63; /* 1: yes; 0: no */
return (unsigned char) y;
}
static unsigned char negative(signed char b) {
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
x >>= 63; /* 1: yes; 0: no */
return (unsigned char) x;
}
static void cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) {
fe_cmov(t->yplusx, u->yplusx, b);
fe_cmov(t->yminusx, u->yminusx, b);
fe_cmov(t->xy2d, u->xy2d, b);
}
static void select(ge_precomp *t, int pos, signed char b) {
ge_precomp minust;
unsigned char bnegative = negative(b);
unsigned char babs = b - (((-bnegative) & b) << 1);
fe_1(t->yplusx);
fe_1(t->yminusx);
fe_0(t->xy2d);
cmov(t, &base[pos][0], equal(babs, 1));
cmov(t, &base[pos][1], equal(babs, 2));
cmov(t, &base[pos][2], equal(babs, 3));
cmov(t, &base[pos][3], equal(babs, 4));
cmov(t, &base[pos][4], equal(babs, 5));
cmov(t, &base[pos][5], equal(babs, 6));
cmov(t, &base[pos][6], equal(babs, 7));
cmov(t, &base[pos][7], equal(babs, 8));
fe_copy(minust.yplusx, t->yminusx);
fe_copy(minust.yminusx, t->yplusx);
fe_neg(minust.xy2d, t->xy2d);
cmov(t, &minust, bnegative);
}
/*
h = a * B
where a = a[0]+256*a[1]+...+256^31 a[31]
B is the Ed25519 base point (x,4/5) with x positive.
Preconditions:
a[31] <= 127
*/
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
signed char e[64];
signed char carry;
ge_p1p1 r;
ge_p2 s;
ge_precomp t;
int i;
for (i = 0; i < 32; ++i) {
e[2 * i + 0] = (a[i] >> 0) & 15;
e[2 * i + 1] = (a[i] >> 4) & 15;
}
/* each e[i] is between 0 and 15 */
/* e[63] is between 0 and 7 */
carry = 0;
for (i = 0; i < 63; ++i) {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
}
e[63] += carry;
/* each e[i] is between -8 and 8 */
ge_p3_0(h);
for (i = 1; i < 64; i += 2) {
select(&t, i / 2, e[i]);
ge_madd(&r, h, &t);
ge_p1p1_to_p3(h, &r);
}
ge_p3_dbl(&r, h);
ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s);
ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s);
ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s);
ge_p1p1_to_p3(h, &r);
for (i = 0; i < 64; i += 2) {
select(&t, i / 2, e[i]);
ge_madd(&r, h, &t);
ge_p1p1_to_p3(h, &r);
}
}
/*
r = p - q
*/
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
fe_mul(r->Z, r->X, q->YminusX);
fe_mul(r->Y, r->Y, q->YplusX);
fe_mul(r->T, q->T2d, p->T);
fe_mul(r->X, p->Z, q->Z);
fe_add(t0, r->X, r->X);
fe_sub(r->X, r->Z, r->Y);
fe_add(r->Y, r->Z, r->Y);
fe_sub(r->Z, t0, r->T);
fe_add(r->T, t0, r->T);
}
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
fe recip;
fe x;
fe y;
fe_invert(recip, h->Z);
fe_mul(x, h->X, recip);
fe_mul(y, h->Y, recip);
fe_tobytes(s, y);
s[31] ^= fe_isnegative(x) << 7;
}

View File

@@ -1,74 +0,0 @@
#ifndef GE_H
#define GE_H
#include "fe.h"
/*
ge means group element.
Here the group is the set of pairs (x,y) of field elements (see fe.h)
satisfying -x^2 + y^2 = 1 + d x^2y^2
where d = -121665/121666.
Representations:
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
ge_precomp (Duif): (y+x,y-x,2dxy)
*/
typedef struct {
fe X;
fe Y;
fe Z;
} ge_p2;
typedef struct {
fe X;
fe Y;
fe Z;
fe T;
} ge_p3;
typedef struct {
fe X;
fe Y;
fe Z;
fe T;
} ge_p1p1;
typedef struct {
fe yplusx;
fe yminusx;
fe xy2d;
} ge_precomp;
typedef struct {
fe YplusX;
fe YminusX;
fe Z;
fe T2d;
} ge_cached;
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
void ge_tobytes(unsigned char *s, const ge_p2 *h);
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
void ge_p2_0(ge_p2 *h);
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
void ge_p3_0(ge_p3 *h);
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
#endif

View File

@@ -1,79 +0,0 @@
#include "ed25519.h"
#include "fe.h"
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
unsigned char e[32];
unsigned int i;
fe x1;
fe x2;
fe z2;
fe x3;
fe z3;
fe tmp0;
fe tmp1;
int pos;
unsigned int swap;
unsigned int b;
/* copy the private key and make sure it's valid */
for (i = 0; i < 32; ++i) {
e[i] = private_key[i];
}
e[0] &= 248;
e[31] &= 63;
e[31] |= 64;
/* unpack the public key and convert edwards to montgomery */
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
fe_frombytes(x1, public_key);
fe_1(tmp1);
fe_add(tmp0, x1, tmp1);
fe_sub(tmp1, tmp1, x1);
fe_invert(tmp1, tmp1);
fe_mul(x1, tmp0, tmp1);
fe_1(x2);
fe_0(z2);
fe_copy(x3, x1);
fe_1(z3);
swap = 0;
for (pos = 254; pos >= 0; --pos) {
b = e[pos / 8] >> (pos & 7);
b &= 1;
swap ^= b;
fe_cswap(x2, x3, swap);
fe_cswap(z2, z3, swap);
swap = b;
/* from montgomery.h */
fe_sub(tmp0, x3, z3);
fe_sub(tmp1, x2, z2);
fe_add(x2, x2, z2);
fe_add(z2, x3, z3);
fe_mul(z3, tmp0, x2);
fe_mul(z2, z2, tmp1);
fe_sq(tmp0, tmp1);
fe_sq(tmp1, x2);
fe_add(x3, z3, z2);
fe_sub(z2, z3, z2);
fe_mul(x2, tmp1, tmp0);
fe_sub(tmp1, tmp1, tmp0);
fe_sq(z2, z2);
fe_mul121666(z3, tmp1);
fe_sq(x3, x3);
fe_add(tmp0, tmp0, z3);
fe_mul(z3, x1, z2);
fe_mul(z2, tmp1, tmp0);
}
fe_cswap(x2, x3, swap);
fe_cswap(z2, z3, swap);
fe_invert(z2, z2);
fe_mul(x2, x2, z2);
fe_tobytes(shared_secret, x2);
}

View File

@@ -1,16 +0,0 @@
#include "ed25519.h"
#include "sha512.h"
#include "ge.h"
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
ge_p3 A;
sha512(seed, 32, private_key);
private_key[0] &= 248;
private_key[31] &= 63;
private_key[31] |= 64;
ge_scalarmult_base(&A, private_key);
ge_p3_tobytes(public_key, &A);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,809 +0,0 @@
#include "fixedint.h"
#include "sc.h"
static uint64_t load_3(const unsigned char *in) {
uint64_t result;
result = (uint64_t) in[0];
result |= ((uint64_t) in[1]) << 8;
result |= ((uint64_t) in[2]) << 16;
return result;
}
static uint64_t load_4(const unsigned char *in) {
uint64_t result;
result = (uint64_t) in[0];
result |= ((uint64_t) in[1]) << 8;
result |= ((uint64_t) in[2]) << 16;
result |= ((uint64_t) in[3]) << 24;
return result;
}
/*
Input:
s[0]+256*s[1]+...+256^63*s[63] = s
Output:
s[0]+256*s[1]+...+256^31*s[31] = s mod l
where l = 2^252 + 27742317777372353535851937790883648493.
Overwrites s in place.
*/
void sc_reduce(unsigned char *s) {
int64_t s0 = 2097151 & load_3(s);
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
int64_t s8 = 2097151 & load_3(s + 21);
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
int64_t s16 = 2097151 & load_3(s + 42);
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
int64_t s23 = (load_4(s + 60) >> 3);
int64_t carry0;
int64_t carry1;
int64_t carry2;
int64_t carry3;
int64_t carry4;
int64_t carry5;
int64_t carry6;
int64_t carry7;
int64_t carry8;
int64_t carry9;
int64_t carry10;
int64_t carry11;
int64_t carry12;
int64_t carry13;
int64_t carry14;
int64_t carry15;
int64_t carry16;
s11 += s23 * 666643;
s12 += s23 * 470296;
s13 += s23 * 654183;
s14 -= s23 * 997805;
s15 += s23 * 136657;
s16 -= s23 * 683901;
s23 = 0;
s10 += s22 * 666643;
s11 += s22 * 470296;
s12 += s22 * 654183;
s13 -= s22 * 997805;
s14 += s22 * 136657;
s15 -= s22 * 683901;
s22 = 0;
s9 += s21 * 666643;
s10 += s21 * 470296;
s11 += s21 * 654183;
s12 -= s21 * 997805;
s13 += s21 * 136657;
s14 -= s21 * 683901;
s21 = 0;
s8 += s20 * 666643;
s9 += s20 * 470296;
s10 += s20 * 654183;
s11 -= s20 * 997805;
s12 += s20 * 136657;
s13 -= s20 * 683901;
s20 = 0;
s7 += s19 * 666643;
s8 += s19 * 470296;
s9 += s19 * 654183;
s10 -= s19 * 997805;
s11 += s19 * 136657;
s12 -= s19 * 683901;
s19 = 0;
s6 += s18 * 666643;
s7 += s18 * 470296;
s8 += s18 * 654183;
s9 -= s18 * 997805;
s10 += s18 * 136657;
s11 -= s18 * 683901;
s18 = 0;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s5 += s17 * 666643;
s6 += s17 * 470296;
s7 += s17 * 654183;
s8 -= s17 * 997805;
s9 += s17 * 136657;
s10 -= s17 * 683901;
s17 = 0;
s4 += s16 * 666643;
s5 += s16 * 470296;
s6 += s16 * 654183;
s7 -= s16 * 997805;
s8 += s16 * 136657;
s9 -= s16 * 683901;
s16 = 0;
s3 += s15 * 666643;
s4 += s15 * 470296;
s5 += s15 * 654183;
s6 -= s15 * 997805;
s7 += s15 * 136657;
s8 -= s15 * 683901;
s15 = 0;
s2 += s14 * 666643;
s3 += s14 * 470296;
s4 += s14 * 654183;
s5 -= s14 * 997805;
s6 += s14 * 136657;
s7 -= s14 * 683901;
s14 = 0;
s1 += s13 * 666643;
s2 += s13 * 470296;
s3 += s13 * 654183;
s4 -= s13 * 997805;
s5 += s13 * 136657;
s6 -= s13 * 683901;
s13 = 0;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry11 = s11 >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s[0] = (unsigned char) (s0 >> 0);
s[1] = (unsigned char) (s0 >> 8);
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
s[3] = (unsigned char) (s1 >> 3);
s[4] = (unsigned char) (s1 >> 11);
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
s[6] = (unsigned char) (s2 >> 6);
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
s[8] = (unsigned char) (s3 >> 1);
s[9] = (unsigned char) (s3 >> 9);
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
s[11] = (unsigned char) (s4 >> 4);
s[12] = (unsigned char) (s4 >> 12);
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
s[14] = (unsigned char) (s5 >> 7);
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
s[16] = (unsigned char) (s6 >> 2);
s[17] = (unsigned char) (s6 >> 10);
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
s[19] = (unsigned char) (s7 >> 5);
s[20] = (unsigned char) (s7 >> 13);
s[21] = (unsigned char) (s8 >> 0);
s[22] = (unsigned char) (s8 >> 8);
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
s[24] = (unsigned char) (s9 >> 3);
s[25] = (unsigned char) (s9 >> 11);
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
s[27] = (unsigned char) (s10 >> 6);
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
s[29] = (unsigned char) (s11 >> 1);
s[30] = (unsigned char) (s11 >> 9);
s[31] = (unsigned char) (s11 >> 17);
}
/*
Input:
a[0]+256*a[1]+...+256^31*a[31] = a
b[0]+256*b[1]+...+256^31*b[31] = b
c[0]+256*c[1]+...+256^31*c[31] = c
Output:
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
where l = 2^252 + 27742317777372353535851937790883648493.
*/
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
int64_t a0 = 2097151 & load_3(a);
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
int64_t a8 = 2097151 & load_3(a + 21);
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
int64_t a11 = (load_4(a + 28) >> 7);
int64_t b0 = 2097151 & load_3(b);
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
int64_t b8 = 2097151 & load_3(b + 21);
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
int64_t b11 = (load_4(b + 28) >> 7);
int64_t c0 = 2097151 & load_3(c);
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
int64_t c8 = 2097151 & load_3(c + 21);
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
int64_t c11 = (load_4(c + 28) >> 7);
int64_t s0;
int64_t s1;
int64_t s2;
int64_t s3;
int64_t s4;
int64_t s5;
int64_t s6;
int64_t s7;
int64_t s8;
int64_t s9;
int64_t s10;
int64_t s11;
int64_t s12;
int64_t s13;
int64_t s14;
int64_t s15;
int64_t s16;
int64_t s17;
int64_t s18;
int64_t s19;
int64_t s20;
int64_t s21;
int64_t s22;
int64_t s23;
int64_t carry0;
int64_t carry1;
int64_t carry2;
int64_t carry3;
int64_t carry4;
int64_t carry5;
int64_t carry6;
int64_t carry7;
int64_t carry8;
int64_t carry9;
int64_t carry10;
int64_t carry11;
int64_t carry12;
int64_t carry13;
int64_t carry14;
int64_t carry15;
int64_t carry16;
int64_t carry17;
int64_t carry18;
int64_t carry19;
int64_t carry20;
int64_t carry21;
int64_t carry22;
s0 = c0 + a0 * b0;
s1 = c1 + a0 * b1 + a1 * b0;
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
s20 = a9 * b11 + a10 * b10 + a11 * b9;
s21 = a10 * b11 + a11 * b10;
s22 = a11 * b11;
s23 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
carry18 = (s18 + (1 << 20)) >> 21;
s19 += carry18;
s18 -= carry18 << 21;
carry20 = (s20 + (1 << 20)) >> 21;
s21 += carry20;
s20 -= carry20 << 21;
carry22 = (s22 + (1 << 20)) >> 21;
s23 += carry22;
s22 -= carry22 << 21;
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
carry17 = (s17 + (1 << 20)) >> 21;
s18 += carry17;
s17 -= carry17 << 21;
carry19 = (s19 + (1 << 20)) >> 21;
s20 += carry19;
s19 -= carry19 << 21;
carry21 = (s21 + (1 << 20)) >> 21;
s22 += carry21;
s21 -= carry21 << 21;
s11 += s23 * 666643;
s12 += s23 * 470296;
s13 += s23 * 654183;
s14 -= s23 * 997805;
s15 += s23 * 136657;
s16 -= s23 * 683901;
s23 = 0;
s10 += s22 * 666643;
s11 += s22 * 470296;
s12 += s22 * 654183;
s13 -= s22 * 997805;
s14 += s22 * 136657;
s15 -= s22 * 683901;
s22 = 0;
s9 += s21 * 666643;
s10 += s21 * 470296;
s11 += s21 * 654183;
s12 -= s21 * 997805;
s13 += s21 * 136657;
s14 -= s21 * 683901;
s21 = 0;
s8 += s20 * 666643;
s9 += s20 * 470296;
s10 += s20 * 654183;
s11 -= s20 * 997805;
s12 += s20 * 136657;
s13 -= s20 * 683901;
s20 = 0;
s7 += s19 * 666643;
s8 += s19 * 470296;
s9 += s19 * 654183;
s10 -= s19 * 997805;
s11 += s19 * 136657;
s12 -= s19 * 683901;
s19 = 0;
s6 += s18 * 666643;
s7 += s18 * 470296;
s8 += s18 * 654183;
s9 -= s18 * 997805;
s10 += s18 * 136657;
s11 -= s18 * 683901;
s18 = 0;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry12 = (s12 + (1 << 20)) >> 21;
s13 += carry12;
s12 -= carry12 << 21;
carry14 = (s14 + (1 << 20)) >> 21;
s15 += carry14;
s14 -= carry14 << 21;
carry16 = (s16 + (1 << 20)) >> 21;
s17 += carry16;
s16 -= carry16 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
carry13 = (s13 + (1 << 20)) >> 21;
s14 += carry13;
s13 -= carry13 << 21;
carry15 = (s15 + (1 << 20)) >> 21;
s16 += carry15;
s15 -= carry15 << 21;
s5 += s17 * 666643;
s6 += s17 * 470296;
s7 += s17 * 654183;
s8 -= s17 * 997805;
s9 += s17 * 136657;
s10 -= s17 * 683901;
s17 = 0;
s4 += s16 * 666643;
s5 += s16 * 470296;
s6 += s16 * 654183;
s7 -= s16 * 997805;
s8 += s16 * 136657;
s9 -= s16 * 683901;
s16 = 0;
s3 += s15 * 666643;
s4 += s15 * 470296;
s5 += s15 * 654183;
s6 -= s15 * 997805;
s7 += s15 * 136657;
s8 -= s15 * 683901;
s15 = 0;
s2 += s14 * 666643;
s3 += s14 * 470296;
s4 += s14 * 654183;
s5 -= s14 * 997805;
s6 += s14 * 136657;
s7 -= s14 * 683901;
s14 = 0;
s1 += s13 * 666643;
s2 += s13 * 470296;
s3 += s13 * 654183;
s4 -= s13 * 997805;
s5 += s13 * 136657;
s6 -= s13 * 683901;
s13 = 0;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = (s0 + (1 << 20)) >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry2 = (s2 + (1 << 20)) >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry4 = (s4 + (1 << 20)) >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry6 = (s6 + (1 << 20)) >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry8 = (s8 + (1 << 20)) >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry10 = (s10 + (1 << 20)) >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry1 = (s1 + (1 << 20)) >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry3 = (s3 + (1 << 20)) >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry5 = (s5 + (1 << 20)) >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry7 = (s7 + (1 << 20)) >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry9 = (s9 + (1 << 20)) >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry11 = (s11 + (1 << 20)) >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
carry11 = s11 >> 21;
s12 += carry11;
s11 -= carry11 << 21;
s0 += s12 * 666643;
s1 += s12 * 470296;
s2 += s12 * 654183;
s3 -= s12 * 997805;
s4 += s12 * 136657;
s5 -= s12 * 683901;
s12 = 0;
carry0 = s0 >> 21;
s1 += carry0;
s0 -= carry0 << 21;
carry1 = s1 >> 21;
s2 += carry1;
s1 -= carry1 << 21;
carry2 = s2 >> 21;
s3 += carry2;
s2 -= carry2 << 21;
carry3 = s3 >> 21;
s4 += carry3;
s3 -= carry3 << 21;
carry4 = s4 >> 21;
s5 += carry4;
s4 -= carry4 << 21;
carry5 = s5 >> 21;
s6 += carry5;
s5 -= carry5 << 21;
carry6 = s6 >> 21;
s7 += carry6;
s6 -= carry6 << 21;
carry7 = s7 >> 21;
s8 += carry7;
s7 -= carry7 << 21;
carry8 = s8 >> 21;
s9 += carry8;
s8 -= carry8 << 21;
carry9 = s9 >> 21;
s10 += carry9;
s9 -= carry9 << 21;
carry10 = s10 >> 21;
s11 += carry10;
s10 -= carry10 << 21;
s[0] = (unsigned char) (s0 >> 0);
s[1] = (unsigned char) (s0 >> 8);
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
s[3] = (unsigned char) (s1 >> 3);
s[4] = (unsigned char) (s1 >> 11);
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
s[6] = (unsigned char) (s2 >> 6);
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
s[8] = (unsigned char) (s3 >> 1);
s[9] = (unsigned char) (s3 >> 9);
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
s[11] = (unsigned char) (s4 >> 4);
s[12] = (unsigned char) (s4 >> 12);
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
s[14] = (unsigned char) (s5 >> 7);
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
s[16] = (unsigned char) (s6 >> 2);
s[17] = (unsigned char) (s6 >> 10);
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
s[19] = (unsigned char) (s7 >> 5);
s[20] = (unsigned char) (s7 >> 13);
s[21] = (unsigned char) (s8 >> 0);
s[22] = (unsigned char) (s8 >> 8);
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
s[24] = (unsigned char) (s9 >> 3);
s[25] = (unsigned char) (s9 >> 11);
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
s[27] = (unsigned char) (s10 >> 6);
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
s[29] = (unsigned char) (s11 >> 1);
s[30] = (unsigned char) (s11 >> 9);
s[31] = (unsigned char) (s11 >> 17);
}

View File

@@ -1,12 +0,0 @@
#ifndef SC_H
#define SC_H
/*
The set of scalars is \Z/l
where l = 2^252 + 27742317777372353535851937790883648493.
*/
void sc_reduce(unsigned char *s);
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
#endif

View File

@@ -1,40 +0,0 @@
#include "ed25519.h"
#ifndef ED25519_NO_SEED
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
#else
#include <stdio.h>
#endif
int ed25519_create_seed(unsigned char *seed) {
#ifdef _WIN32
HCRYPTPROV prov;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
return 1;
}
if (!CryptGenRandom(prov, 32, seed)) {
CryptReleaseContext(prov, 0);
return 1;
}
CryptReleaseContext(prov, 0);
#else
FILE *f = fopen("/dev/urandom", "rb");
if (f == NULL) {
return 1;
}
fread(seed, 1, 32, f);
fclose(f);
#endif
return 0;
}
#endif

View File

@@ -1,275 +0,0 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "fixedint.h"
#include "sha512.h"
/* the K array */
static const uint64_t K[80] = {
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
};
/* Various logical functions */
#define ROR64c(x, y) \
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
#define STORE64H(x, y) \
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
#define LOAD64H(x, y) \
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
#ifndef MIN
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
#endif
/* compress 1024-bits */
static int sha512_compress(sha512_context *md, unsigned char *buf)
{
uint64_t S[8], W[80], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 1024-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8*i));
}
/* fill W[16..79] */
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c);\
d += t0; \
h = t0 + t1;
for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
}
#undef RND
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
return 0;
}
/**
Initialize the hash state
@param md The hash state you wish to initialize
@return 0 if successful
*/
int sha512_init(sha512_context * md) {
if (md == NULL) return 1;
md->curlen = 0;
md->length = 0;
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
md->state[4] = UINT64_C(0x510e527fade682d1);
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
md->state[7] = UINT64_C(0x5be0cd19137e2179);
return 0;
}
/**
Process a block of memory though the hash
@param md The hash state
@param in The data to hash
@param inlen The length of the data (octets)
@return 0 if successful
*/
int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
{
size_t n;
size_t i;
int err;
if (md == NULL) return 1;
if (in == NULL) return 1;
if (md->curlen > sizeof(md->buf)) {
return 1;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
return err;
}
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
n = MIN(inlen, (128 - md->curlen));
for (i = 0; i < n; i++) {
md->buf[i + md->curlen] = in[i];
}
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
if ((err = sha512_compress (md, md->buf)) != 0) {
return err;
}
md->length += 8*128;
md->curlen = 0;
}
}
}
return 0;
}
/**
Terminate the hash to get the digest
@param md The hash state
@param out [out] The destination of the hash (64 bytes)
@return 0 if successful
*/
int sha512_final(sha512_context * md, unsigned char *out)
{
int i;
if (md == NULL) return 1;
if (out == NULL) return 1;
if (md->curlen >= sizeof(md->buf)) {
return 1;
}
/* increase the length of the message */
md->length += md->curlen * UINT64_C(8);
/* append the '1' bit */
md->buf[md->curlen++] = (unsigned char)0x80;
/* if the length is currently above 112 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 112) {
while (md->curlen < 128) {
md->buf[md->curlen++] = (unsigned char)0;
}
sha512_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 120 bytes of zeroes
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
* > 2^64 bits of data... :-)
*/
while (md->curlen < 120) {
md->buf[md->curlen++] = (unsigned char)0;
}
/* store length */
STORE64H(md->length, md->buf+120);
sha512_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
}
return 0;
}
int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
{
sha512_context ctx;
int ret;
if ((ret = sha512_init(&ctx))) return ret;
if ((ret = sha512_update(&ctx, message, message_len))) return ret;
if ((ret = sha512_final(&ctx, out))) return ret;
return 0;
}

View File

@@ -1,28 +0,0 @@
#ifndef SHA512_H
#define SHA512_H
#include <stddef.h>
#include "fixedint.h"
/* state */
typedef struct sha512_context_ {
uint64_t length, state[8];
size_t curlen;
unsigned char buf[128];
} sha512_context;
#ifdef __cplusplus
extern "C" {
#endif
int sha512_init(sha512_context * md);
int sha512_final(sha512_context * md, unsigned char *out);
int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,31 +0,0 @@
#include "ed25519.h"
#include "sha512.h"
#include "ge.h"
#include "sc.h"
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
sha512_context hash;
unsigned char hram[64];
unsigned char r[64];
ge_p3 R;
sha512_init(&hash);
sha512_update(&hash, private_key + 32, 32);
sha512_update(&hash, message, message_len);
sha512_final(&hash, r);
sc_reduce(r);
ge_scalarmult_base(&R, r);
ge_p3_tobytes(signature, &R);
sha512_init(&hash);
sha512_update(&hash, signature, 32);
sha512_update(&hash, public_key, 32);
sha512_update(&hash, message, message_len);
sha512_final(&hash, hram);
sc_reduce(hram);
sc_muladd(signature + 32, hram, private_key, r);
}

View File

@@ -1,77 +0,0 @@
#include "ed25519.h"
#include "sha512.h"
#include "ge.h"
#include "sc.h"
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
unsigned char r = 0;
r = x[0] ^ y[0];
#define F(i) r |= x[i] ^ y[i]
F(1);
F(2);
F(3);
F(4);
F(5);
F(6);
F(7);
F(8);
F(9);
F(10);
F(11);
F(12);
F(13);
F(14);
F(15);
F(16);
F(17);
F(18);
F(19);
F(20);
F(21);
F(22);
F(23);
F(24);
F(25);
F(26);
F(27);
F(28);
F(29);
F(30);
F(31);
#undef F
return !r;
}
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
unsigned char h[64];
unsigned char checker[32];
sha512_context hash;
ge_p3 A;
ge_p2 R;
if (signature[63] & 224) {
return 0;
}
if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
return 0;
}
sha512_init(&hash);
sha512_update(&hash, signature, 32);
sha512_update(&hash, public_key, 32);
sha512_update(&hash, message, message_len);
sha512_final(&hash, h);
sc_reduce(h);
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
ge_tobytes(checker, &R);
if (!consttime_equal(checker, signature)) {
return 0;
}
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,455 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef http_parser_h
#define http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 9
#define HTTP_PARSER_VERSION_PATCH 3
#include <stddef.h>
#if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 0
#endif
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
* returning '1' from on_headers_complete will tell the parser that it
* should not expect a body. This is used when receiving a response to a
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body.
*
* Returning `2` from on_headers_complete will tell parser that it should not
* expect neither a body nor any futher responses on this connection. This is
* useful for handling responses to a CONNECT request which may not contain
* `Upgrade` or `Connection: upgrade` headers.
*
* http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
/* Status Codes */
#define HTTP_STATUS_MAP(XX) \
XX(100, CONTINUE, Continue) \
XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
XX(102, PROCESSING, Processing) \
XX(200, OK, OK) \
XX(201, CREATED, Created) \
XX(202, ACCEPTED, Accepted) \
XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
XX(204, NO_CONTENT, No Content) \
XX(205, RESET_CONTENT, Reset Content) \
XX(206, PARTIAL_CONTENT, Partial Content) \
XX(207, MULTI_STATUS, Multi-Status) \
XX(208, ALREADY_REPORTED, Already Reported) \
XX(226, IM_USED, IM Used) \
XX(300, MULTIPLE_CHOICES, Multiple Choices) \
XX(301, MOVED_PERMANENTLY, Moved Permanently) \
XX(302, FOUND, Found) \
XX(303, SEE_OTHER, See Other) \
XX(304, NOT_MODIFIED, Not Modified) \
XX(305, USE_PROXY, Use Proxy) \
XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
XX(400, BAD_REQUEST, Bad Request) \
XX(401, UNAUTHORIZED, Unauthorized) \
XX(402, PAYMENT_REQUIRED, Payment Required) \
XX(403, FORBIDDEN, Forbidden) \
XX(404, NOT_FOUND, Not Found) \
XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
XX(406, NOT_ACCEPTABLE, Not Acceptable) \
XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
XX(408, REQUEST_TIMEOUT, Request Timeout) \
XX(409, CONFLICT, Conflict) \
XX(410, GONE, Gone) \
XX(411, LENGTH_REQUIRED, Length Required) \
XX(412, PRECONDITION_FAILED, Precondition Failed) \
XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
XX(414, URI_TOO_LONG, URI Too Long) \
XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
XX(417, EXPECTATION_FAILED, Expectation Failed) \
XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
XX(423, LOCKED, Locked) \
XX(424, FAILED_DEPENDENCY, Failed Dependency) \
XX(426, UPGRADE_REQUIRED, Upgrade Required) \
XX(428, PRECONDITION_REQUIRED, Precondition Required) \
XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
XX(501, NOT_IMPLEMENTED, Not Implemented) \
XX(502, BAD_GATEWAY, Bad Gateway) \
XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
XX(508, LOOP_DETECTED, Loop Detected) \
XX(510, NOT_EXTENDED, Not Extended) \
XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
enum http_status
{
#define XX(num, name, string) HTTP_STATUS_##name = num,
HTTP_STATUS_MAP(XX)
#undef XX
};
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* WebDAV */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
/* subversion */ \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
/* upnp */ \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
/* CalDAV */ \
XX(30, MKCALENDAR, MKCALENDAR) \
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
/* icecast */ \
XX(33, SOURCE, SOURCE) \
/* RFC-2326 (RTSP) */ \
XX(34, DESCRIBE, DESCRIBE) \
XX(35, ANNOUNCE, ANNOUNCE) \
XX(36, SETUP, SETUP) \
XX(37, PLAY, PLAY) \
XX(38, PAUSE, PAUSE) \
XX(39, TEARDOWN, TEARDOWN) \
XX(40, GET_PARAMETER, GET_PARAMETER) \
XX(41, SET_PARAMETER, SET_PARAMETER) \
XX(42, REDIRECT, REDIRECT) \
XX(43, RECORD, RECORD) \
/* RAOP */ \
XX(44, FLUSH, FLUSH) \
enum http_method
{
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
#undef XX
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
, F_CONTENTLENGTH = 1 << 7
, F_TRANSFER_ENCODING = 1 << 8
};
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
XX(CB_chunk_header, "the on_chunk_header callback failed") \
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(UNEXPECTED_CONTENT_LENGTH, \
"unexpected content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_TRANSFER_ENCODING, \
"request has invalid transfer-encoding") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 7; /* enum header_state from http_parser.c */
unsigned int index : 7; /* index into current matcher */
unsigned int lenient_http_headers : 1;
unsigned int flags : 16; /* F_* values from 'flags' enum; semi-public */
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
* unsigned long version = http_parser_version();
* unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns 0, then this should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Returns a string version of the HTTP status code. */
const char *http_status_str(enum http_status s);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
/* Change the maximum header size provided at compile time. */
void http_parser_set_max_header_size(uint32_t size);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -17,11 +17,11 @@
#include <assert.h>
#include "http_request.h"
#include "http_parser.h"
#include "llhttp/llhttp.h"
struct http_request_s {
http_parser parser;
http_parser_settings parser_settings;
llhttp_t parser;
llhttp_settings_t parser_settings;
const char *method;
char *url;
@@ -37,7 +37,7 @@ struct http_request_s {
};
static int
on_url(http_parser *parser, const char *at, size_t length)
on_url(llhttp_t *parser, const char *at, size_t length)
{
http_request_t *request = parser->data;
int urllen = request->url ? strlen(request->url) : 0;
@@ -51,7 +51,7 @@ on_url(http_parser *parser, const char *at, size_t length)
}
static int
on_header_field(http_parser *parser, const char *at, size_t length)
on_header_field(llhttp_t *parser, const char *at, size_t length)
{
http_request_t *request = parser->data;
@@ -86,7 +86,7 @@ on_header_field(http_parser *parser, const char *at, size_t length)
}
static int
on_header_value(http_parser *parser, const char *at, size_t length)
on_header_value(llhttp_t *parser, const char *at, size_t length)
{
http_request_t *request = parser->data;
@@ -111,7 +111,7 @@ on_header_value(http_parser *parser, const char *at, size_t length)
}
static int
on_body(http_parser *parser, const char *at, size_t length)
on_body(llhttp_t *parser, const char *at, size_t length)
{
http_request_t *request = parser->data;
@@ -124,11 +124,11 @@ on_body(http_parser *parser, const char *at, size_t length)
}
static int
on_message_complete(http_parser *parser)
on_message_complete(llhttp_t *parser)
{
http_request_t *request = parser->data;
request->method = http_method_str(request->parser.method);
request->method = llhttp_method_name(request->parser.method);
request->complete = 1;
return 0;
}
@@ -142,15 +142,17 @@ http_request_init(void)
if (!request) {
return NULL;
}
http_parser_init(&request->parser, HTTP_REQUEST);
request->parser.data = request;
llhttp_settings_init(&request->parser_settings);
request->parser_settings.on_url = &on_url;
request->parser_settings.on_header_field = &on_header_field;
request->parser_settings.on_header_value = &on_header_value;
request->parser_settings.on_body = &on_body;
request->parser_settings.on_message_complete = &on_message_complete;
llhttp_init(&request->parser, HTTP_REQUEST, &request->parser_settings);
request->parser.data = request;
return request;
}
@@ -177,8 +179,7 @@ http_request_add_data(http_request_t *request, const char *data, int datalen)
assert(request);
ret = http_parser_execute(&request->parser,
&request->parser_settings,
ret = llhttp_execute(&request->parser,
data, datalen);
return ret;
}
@@ -194,21 +195,21 @@ int
http_request_has_error(http_request_t *request)
{
assert(request);
return (HTTP_PARSER_ERRNO(&request->parser) != HPE_OK);
return (llhttp_get_errno(&request->parser) != HPE_OK);
}
const char *
http_request_get_error_name(http_request_t *request)
{
assert(request);
return http_errno_name(HTTP_PARSER_ERRNO(&request->parser));
return llhttp_errno_name(llhttp_get_errno(&request->parser));
}
const char *
http_request_get_error_description(http_request_t *request)
{
assert(request);
return http_errno_description(HTTP_PARSER_ERRNO(&request->parser));
return llhttp_get_error_reason(&request->parser);
}
const char *

7
lib/llhttp/CMakeLists.txt Executable file
View File

@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. llhttp_src)
set(DIR_SRCS ${llhttp_src})
include_directories(.)
add_library( llhttp
STATIC
${DIR_SRCS})

22
lib/llhttp/LICENSE-MIT Normal file
View File

@@ -0,0 +1,22 @@
This software is licensed under the MIT License.
Copyright Fedor Indutny, 2018.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

363
lib/llhttp/api.c Normal file
View File

@@ -0,0 +1,363 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "llhttp.h"
#define CALLBACK_MAYBE(PARSER, NAME) \
do { \
const llhttp_settings_t* settings; \
settings = (const llhttp_settings_t*) (PARSER)->settings; \
if (settings == NULL || settings->NAME == NULL) { \
err = 0; \
break; \
} \
err = settings->NAME((PARSER)); \
} while (0)
#define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \
do { \
const llhttp_settings_t* settings; \
settings = (const llhttp_settings_t*) (PARSER)->settings; \
if (settings == NULL || settings->NAME == NULL) { \
err = 0; \
break; \
} \
err = settings->NAME((PARSER), (START), (LEN)); \
if (err == -1) { \
err = HPE_USER; \
llhttp_set_error_reason((PARSER), "Span callback error in " #NAME); \
} \
} while (0)
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings) {
llhttp__internal_init(parser);
parser->type = type;
parser->settings = (void*) settings;
}
#if defined(__wasm__)
extern int wasm_on_message_begin(llhttp_t * p);
extern int wasm_on_url(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_status(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_headers_complete(llhttp_t * p);
extern int wasm_on_body(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_message_complete(llhttp_t * p);
const llhttp_settings_t wasm_settings = {
wasm_on_message_begin,
wasm_on_url,
wasm_on_status,
wasm_on_header_field,
wasm_on_header_value,
wasm_on_headers_complete,
wasm_on_body,
wasm_on_message_complete,
NULL,
NULL,
};
llhttp_t* llhttp_alloc(llhttp_type_t type) {
llhttp_t* parser = malloc(sizeof(llhttp_t));
llhttp_init(parser, type, &wasm_settings);
return parser;
}
void llhttp_free(llhttp_t* parser) {
free(parser);
}
/* Some getters required to get stuff from the parser */
uint8_t llhttp_get_type(llhttp_t* parser) {
return parser->type;
}
uint8_t llhttp_get_http_major(llhttp_t* parser) {
return parser->http_major;
}
uint8_t llhttp_get_http_minor(llhttp_t* parser) {
return parser->http_minor;
}
uint8_t llhttp_get_method(llhttp_t* parser) {
return parser->method;
}
int llhttp_get_status_code(llhttp_t* parser) {
return parser->status_code;
}
uint8_t llhttp_get_upgrade(llhttp_t* parser) {
return parser->upgrade;
}
#endif // defined(__wasm__)
void llhttp_reset(llhttp_t* parser) {
llhttp_type_t type = parser->type;
const llhttp_settings_t* settings = parser->settings;
void* data = parser->data;
uint8_t lenient_flags = parser->lenient_flags;
llhttp__internal_init(parser);
parser->type = type;
parser->settings = (void*) settings;
parser->data = data;
parser->lenient_flags = lenient_flags;
}
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) {
return llhttp__internal_execute(parser, data, data + len);
}
void llhttp_settings_init(llhttp_settings_t* settings) {
memset(settings, 0, sizeof(*settings));
}
llhttp_errno_t llhttp_finish(llhttp_t* parser) {
int err;
/* We're in an error state. Don't bother doing anything. */
if (parser->error != 0) {
return 0;
}
switch (parser->finish) {
case HTTP_FINISH_SAFE_WITH_CB:
CALLBACK_MAYBE(parser, on_message_complete);
if (err != HPE_OK) return err;
/* FALLTHROUGH */
case HTTP_FINISH_SAFE:
return HPE_OK;
case HTTP_FINISH_UNSAFE:
parser->reason = "Invalid EOF state";
return HPE_INVALID_EOF_STATE;
default:
abort();
}
}
void llhttp_pause(llhttp_t* parser) {
if (parser->error != HPE_OK) {
return;
}
parser->error = HPE_PAUSED;
parser->reason = "Paused";
}
void llhttp_resume(llhttp_t* parser) {
if (parser->error != HPE_PAUSED) {
return;
}
parser->error = 0;
}
void llhttp_resume_after_upgrade(llhttp_t* parser) {
if (parser->error != HPE_PAUSED_UPGRADE) {
return;
}
parser->error = 0;
}
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) {
return parser->error;
}
const char* llhttp_get_error_reason(const llhttp_t* parser) {
return parser->reason;
}
void llhttp_set_error_reason(llhttp_t* parser, const char* reason) {
parser->reason = reason;
}
const char* llhttp_get_error_pos(const llhttp_t* parser) {
return parser->error_pos;
}
const char* llhttp_errno_name(llhttp_errno_t err) {
#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME;
switch (err) {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
default: abort();
}
#undef HTTP_ERRNO_GEN
}
const char* llhttp_method_name(llhttp_method_t method) {
#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING;
switch (method) {
HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN)
default: abort();
}
#undef HTTP_METHOD_GEN
}
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_HEADERS;
} else {
parser->lenient_flags &= ~LENIENT_HEADERS;
}
}
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_CHUNKED_LENGTH;
} else {
parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH;
}
}
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_KEEP_ALIVE;
} else {
parser->lenient_flags &= ~LENIENT_KEEP_ALIVE;
}
}
/* Callbacks */
int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_message_begin);
return err;
}
int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p);
return err;
}
int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_url_complete);
return err;
}
int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p);
return err;
}
int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_status_complete);
return err;
}
int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p);
return err;
}
int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_field_complete);
return err;
}
int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p);
return err;
}
int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_value_complete);
return err;
}
int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_headers_complete);
return err;
}
int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_message_complete);
return err;
}
int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) {
int err;
SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p);
return err;
}
int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_header);
return err;
}
int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_complete);
return err;
}
/* Private */
void llhttp__debug(llhttp_t* s, const char* p, const char* endp,
const char* msg) {
if (p == endp) {
fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type,
s->flags, msg);
} else {
fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s,
s->type, s->flags, *p, msg);
}
}

149
lib/llhttp/http.c Normal file
View File

@@ -0,0 +1,149 @@
#include <stdio.h>
#ifndef LLHTTP__TEST
# include "llhttp.h"
#else
# define llhttp_t llparse_t
#endif /* */
int llhttp_message_needs_eof(const llhttp_t* parser);
int llhttp_should_keep_alive(const llhttp_t* parser);
int llhttp__before_headers_complete(llhttp_t* parser, const char* p,
const char* endp) {
/* Set this here so that on_headers_complete() callbacks can see it */
if ((parser->flags & F_UPGRADE) &&
(parser->flags & F_CONNECTION_UPGRADE)) {
/* For responses, "Upgrade: foo" and "Connection: upgrade" are
* mandatory only when it is a 101 Switching Protocols response,
* otherwise it is purely informational, to announce support.
*/
parser->upgrade =
(parser->type == HTTP_REQUEST || parser->status_code == 101);
} else {
parser->upgrade = (parser->method == HTTP_CONNECT);
}
return 0;
}
/* Return values:
* 0 - No body, `restart`, message_complete
* 1 - CONNECT request, `restart`, message_complete, and pause
* 2 - chunk_size_start
* 3 - body_identity
* 4 - body_identity_eof
* 5 - invalid transfer-encoding for request
*/
int llhttp__after_headers_complete(llhttp_t* parser, const char* p,
const char* endp) {
int hasBody;
hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;
if (parser->upgrade && (parser->method == HTTP_CONNECT ||
(parser->flags & F_SKIPBODY) || !hasBody)) {
/* Exit, the rest of the message is in a different protocol. */
return 1;
}
if (parser->flags & F_SKIPBODY) {
return 0;
} else if (parser->flags & F_CHUNKED) {
/* chunked encoding - ignore Content-Length header, prepare for a chunk */
return 2;
} else if (parser->flags & F_TRANSFER_ENCODING) {
if (parser->type == HTTP_REQUEST &&
(parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0) {
/* RFC 7230 3.3.3 */
/* If a Transfer-Encoding header field
* is present in a request and the chunked transfer coding is not
* the final encoding, the message body length cannot be determined
* reliably; the server MUST respond with the 400 (Bad Request)
* status code and then close the connection.
*/
return 5;
} else {
/* RFC 7230 3.3.3 */
/* If a Transfer-Encoding header field is present in a response and
* the chunked transfer coding is not the final encoding, the
* message body length is determined by reading the connection until
* it is closed by the server.
*/
return 4;
}
} else {
if (!(parser->flags & F_CONTENT_LENGTH)) {
if (!llhttp_message_needs_eof(parser)) {
/* Assume content-length 0 - read the next */
return 0;
} else {
/* Read body until EOF */
return 4;
}
} else if (parser->content_length == 0) {
/* Content-Length header given but zero: Content-Length: 0\r\n */
return 0;
} else {
/* Content-Length header given and non-zero */
return 3;
}
}
}
int llhttp__after_message_complete(llhttp_t* parser, const char* p,
const char* endp) {
int should_keep_alive;
should_keep_alive = llhttp_should_keep_alive(parser);
parser->finish = HTTP_FINISH_SAFE;
parser->flags = 0;
/* NOTE: this is ignored in loose parsing mode */
return should_keep_alive;
}
int llhttp_message_needs_eof(const llhttp_t* parser) {
if (parser->type == HTTP_REQUEST) {
return 0;
}
/* See RFC 2616 section 4.4 */
if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
parser->status_code == 204 || /* No Content */
parser->status_code == 304 || /* Not Modified */
(parser->flags & F_SKIPBODY)) { /* response to a HEAD request */
return 0;
}
/* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */
if ((parser->flags & F_TRANSFER_ENCODING) &&
(parser->flags & F_CHUNKED) == 0) {
return 1;
}
if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {
return 0;
}
return 1;
}
int llhttp_should_keep_alive(const llhttp_t* parser) {
if (parser->http_major > 0 && parser->http_minor > 0) {
/* HTTP/1.1 */
if (parser->flags & F_CONNECTION_CLOSE) {
return 0;
}
} else {
/* HTTP/1.0 or earlier */
if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
return 0;
}
}
return !llhttp_message_needs_eof(parser);
}

14926
lib/llhttp/llhttp.c Normal file

File diff suppressed because it is too large Load Diff

564
lib/llhttp/llhttp.h Normal file
View File

@@ -0,0 +1,564 @@
#ifndef INCLUDE_LLHTTP_H_
#define INCLUDE_LLHTTP_H_
#define LLHTTP_VERSION_MAJOR 6
#define LLHTTP_VERSION_MINOR 0
#define LLHTTP_VERSION_PATCH 2
#ifndef LLHTTP_STRICT_MODE
# define LLHTTP_STRICT_MODE 0
#endif
#ifndef INCLUDE_LLHTTP_ITSELF_H_
#define INCLUDE_LLHTTP_ITSELF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct llhttp__internal_s llhttp__internal_t;
struct llhttp__internal_s {
int32_t _index;
void* _span_pos0;
void* _span_cb0;
int32_t error;
const char* reason;
const char* error_pos;
void* data;
void* _current;
uint64_t content_length;
uint8_t type;
uint8_t method;
uint8_t http_major;
uint8_t http_minor;
uint8_t header_state;
uint8_t lenient_flags;
uint8_t upgrade;
uint8_t finish;
uint16_t flags;
uint16_t status_code;
void* settings;
};
int llhttp__internal_init(llhttp__internal_t* s);
int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_ITSELF_H_ */
#ifndef LLLLHTTP_C_HEADERS_
#define LLLLHTTP_C_HEADERS_
#ifdef __cplusplus
extern "C" {
#endif
enum llhttp_errno {
HPE_OK = 0,
HPE_INTERNAL = 1,
HPE_STRICT = 2,
HPE_LF_EXPECTED = 3,
HPE_UNEXPECTED_CONTENT_LENGTH = 4,
HPE_CLOSED_CONNECTION = 5,
HPE_INVALID_METHOD = 6,
HPE_INVALID_URL = 7,
HPE_INVALID_CONSTANT = 8,
HPE_INVALID_VERSION = 9,
HPE_INVALID_HEADER_TOKEN = 10,
HPE_INVALID_CONTENT_LENGTH = 11,
HPE_INVALID_CHUNK_SIZE = 12,
HPE_INVALID_STATUS = 13,
HPE_INVALID_EOF_STATE = 14,
HPE_INVALID_TRANSFER_ENCODING = 15,
HPE_CB_MESSAGE_BEGIN = 16,
HPE_CB_HEADERS_COMPLETE = 17,
HPE_CB_MESSAGE_COMPLETE = 18,
HPE_CB_CHUNK_HEADER = 19,
HPE_CB_CHUNK_COMPLETE = 20,
HPE_PAUSED = 21,
HPE_PAUSED_UPGRADE = 22,
HPE_PAUSED_H2_UPGRADE = 23,
HPE_USER = 24
};
typedef enum llhttp_errno llhttp_errno_t;
enum llhttp_flags {
F_CONNECTION_KEEP_ALIVE = 0x1,
F_CONNECTION_CLOSE = 0x2,
F_CONNECTION_UPGRADE = 0x4,
F_CHUNKED = 0x8,
F_UPGRADE = 0x10,
F_CONTENT_LENGTH = 0x20,
F_SKIPBODY = 0x40,
F_TRAILING = 0x80,
F_TRANSFER_ENCODING = 0x200
};
typedef enum llhttp_flags llhttp_flags_t;
enum llhttp_lenient_flags {
LENIENT_HEADERS = 0x1,
LENIENT_CHUNKED_LENGTH = 0x2,
LENIENT_KEEP_ALIVE = 0x4
};
typedef enum llhttp_lenient_flags llhttp_lenient_flags_t;
enum llhttp_type {
HTTP_BOTH = 0,
HTTP_REQUEST = 1,
HTTP_RESPONSE = 2
};
typedef enum llhttp_type llhttp_type_t;
enum llhttp_finish {
HTTP_FINISH_SAFE = 0,
HTTP_FINISH_SAFE_WITH_CB = 1,
HTTP_FINISH_UNSAFE = 2
};
typedef enum llhttp_finish llhttp_finish_t;
enum llhttp_method {
HTTP_DELETE = 0,
HTTP_GET = 1,
HTTP_HEAD = 2,
HTTP_POST = 3,
HTTP_PUT = 4,
HTTP_CONNECT = 5,
HTTP_OPTIONS = 6,
HTTP_TRACE = 7,
HTTP_COPY = 8,
HTTP_LOCK = 9,
HTTP_MKCOL = 10,
HTTP_MOVE = 11,
HTTP_PROPFIND = 12,
HTTP_PROPPATCH = 13,
HTTP_SEARCH = 14,
HTTP_UNLOCK = 15,
HTTP_BIND = 16,
HTTP_REBIND = 17,
HTTP_UNBIND = 18,
HTTP_ACL = 19,
HTTP_REPORT = 20,
HTTP_MKACTIVITY = 21,
HTTP_CHECKOUT = 22,
HTTP_MERGE = 23,
HTTP_MSEARCH = 24,
HTTP_NOTIFY = 25,
HTTP_SUBSCRIBE = 26,
HTTP_UNSUBSCRIBE = 27,
HTTP_PATCH = 28,
HTTP_PURGE = 29,
HTTP_MKCALENDAR = 30,
HTTP_LINK = 31,
HTTP_UNLINK = 32,
HTTP_SOURCE = 33,
HTTP_PRI = 34,
HTTP_DESCRIBE = 35,
HTTP_ANNOUNCE = 36,
HTTP_SETUP = 37,
HTTP_PLAY = 38,
HTTP_PAUSE = 39,
HTTP_TEARDOWN = 40,
HTTP_GET_PARAMETER = 41,
HTTP_SET_PARAMETER = 42,
HTTP_REDIRECT = 43,
HTTP_RECORD = 44,
HTTP_FLUSH = 45
};
typedef enum llhttp_method llhttp_method_t;
#define HTTP_ERRNO_MAP(XX) \
XX(0, OK, OK) \
XX(1, INTERNAL, INTERNAL) \
XX(2, STRICT, STRICT) \
XX(3, LF_EXPECTED, LF_EXPECTED) \
XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \
XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \
XX(6, INVALID_METHOD, INVALID_METHOD) \
XX(7, INVALID_URL, INVALID_URL) \
XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \
XX(9, INVALID_VERSION, INVALID_VERSION) \
XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \
XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \
XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \
XX(13, INVALID_STATUS, INVALID_STATUS) \
XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \
XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \
XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
XX(21, PAUSED, PAUSED) \
XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \
XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \
XX(24, USER, USER) \
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
XX(30, MKCALENDAR, MKCALENDAR) \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
XX(33, SOURCE, SOURCE) \
#define RTSP_METHOD_MAP(XX) \
XX(1, GET, GET) \
XX(3, POST, POST) \
XX(6, OPTIONS, OPTIONS) \
XX(35, DESCRIBE, DESCRIBE) \
XX(36, ANNOUNCE, ANNOUNCE) \
XX(37, SETUP, SETUP) \
XX(38, PLAY, PLAY) \
XX(39, PAUSE, PAUSE) \
XX(40, TEARDOWN, TEARDOWN) \
XX(41, GET_PARAMETER, GET_PARAMETER) \
XX(42, SET_PARAMETER, SET_PARAMETER) \
XX(43, REDIRECT, REDIRECT) \
XX(44, RECORD, RECORD) \
XX(45, FLUSH, FLUSH) \
#define HTTP_ALL_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
XX(30, MKCALENDAR, MKCALENDAR) \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
XX(33, SOURCE, SOURCE) \
XX(34, PRI, PRI) \
XX(35, DESCRIBE, DESCRIBE) \
XX(36, ANNOUNCE, ANNOUNCE) \
XX(37, SETUP, SETUP) \
XX(38, PLAY, PLAY) \
XX(39, PAUSE, PAUSE) \
XX(40, TEARDOWN, TEARDOWN) \
XX(41, GET_PARAMETER, GET_PARAMETER) \
XX(42, SET_PARAMETER, SET_PARAMETER) \
XX(43, REDIRECT, REDIRECT) \
XX(44, RECORD, RECORD) \
XX(45, FLUSH, FLUSH) \
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LLLLHTTP_C_HEADERS_ */
#ifndef INCLUDE_LLHTTP_API_H_
#define INCLUDE_LLHTTP_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#if defined(__wasm__)
#define LLHTTP_EXPORT __attribute__((visibility("default")))
#else
#define LLHTTP_EXPORT
#endif
typedef llhttp__internal_t llhttp_t;
typedef struct llhttp_settings_s llhttp_settings_t;
typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);
typedef int (*llhttp_cb)(llhttp_t*);
struct llhttp_settings_s {
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_begin;
/* Possible return values 0, -1, HPE_USER */
llhttp_data_cb on_url;
llhttp_data_cb on_status;
llhttp_data_cb on_header_field;
llhttp_data_cb on_header_value;
/* Possible return values:
* 0 - Proceed normally
* 1 - Assume that request/response has no body, and proceed to parsing the
* next message
* 2 - Assume absence of body (as above) and make `llhttp_execute()` return
* `HPE_PAUSED_UPGRADE`
* -1 - Error
* `HPE_PAUSED`
*/
llhttp_cb on_headers_complete;
/* Possible return values 0, -1, HPE_USER */
llhttp_data_cb on_body;
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
* Possible return values 0, -1, `HPE_PAUSED`
*/
llhttp_cb on_chunk_header;
llhttp_cb on_chunk_complete;
/* Information-only callbacks, return value is ignored */
llhttp_cb on_url_complete;
llhttp_cb on_status_complete;
llhttp_cb on_header_field_complete;
llhttp_cb on_header_value_complete;
};
/* Initialize the parser with specific type and user settings.
*
* NOTE: lifetime of `settings` has to be at least the same as the lifetime of
* the `parser` here. In practice, `settings` has to be either a static
* variable or be allocated with `malloc`, `new`, etc.
*/
LLHTTP_EXPORT
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings);
#if defined(__wasm__)
LLHTTP_EXPORT
llhttp_t* llhttp_alloc(llhttp_type_t type);
LLHTTP_EXPORT
void llhttp_free(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_type(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_major(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_minor(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_method(llhttp_t* parser);
LLHTTP_EXPORT
int llhttp_get_status_code(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_upgrade(llhttp_t* parser);
#endif // defined(__wasm__)
/* Reset an already initialized parser back to the start state, preserving the
* existing parser type, callback settings, user data, and lenient flags.
*/
LLHTTP_EXPORT
void llhttp_reset(llhttp_t* parser);
/* Initialize the settings object */
LLHTTP_EXPORT
void llhttp_settings_init(llhttp_settings_t* settings);
/* Parse full or partial request/response, invoking user callbacks along the
* way.
*
* If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing
* interrupts, and such errno is returned from `llhttp_execute()`. If
* `HPE_PAUSED` was used as a errno, the execution can be resumed with
* `llhttp_resume()` call.
*
* In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`
* is returned after fully parsing the request/response. If the user wishes to
* continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.
*
* NOTE: if this function ever returns a non-pause type error, it will continue
* to return the same error upon each successive call up until `llhttp_init()`
* is called.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
/* This method should be called when the other side has no further bytes to
* send (e.g. shutdown of readable side of the TCP connection.)
*
* Requests without `Content-Length` and other messages might require treating
* all incoming bytes as the part of the body, up to the last byte of the
* connection. This method will invoke `on_message_complete()` callback if the
* request was terminated safely. Otherwise a error code would be returned.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_finish(llhttp_t* parser);
/* Returns `1` if the incoming message is parsed until the last byte, and has
* to be completed by calling `llhttp_finish()` on EOF
*/
LLHTTP_EXPORT
int llhttp_message_needs_eof(const llhttp_t* parser);
/* Returns `1` if there might be any other messages following the last that was
* successfully parsed.
*/
LLHTTP_EXPORT
int llhttp_should_keep_alive(const llhttp_t* parser);
/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set
* appropriate error reason.
*
* Important: do not call this from user callbacks! User callbacks must return
* `HPE_PAUSED` if pausing is required.
*/
LLHTTP_EXPORT
void llhttp_pause(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED`.
*/
LLHTTP_EXPORT
void llhttp_resume(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`
*/
LLHTTP_EXPORT
void llhttp_resume_after_upgrade(llhttp_t* parser);
/* Returns the latest return error */
LLHTTP_EXPORT
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
/* Returns the verbal explanation of the latest returned error.
*
* Note: User callback should set error reason when returning the error. See
* `llhttp_set_error_reason()` for details.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_reason(const llhttp_t* parser);
/* Assign verbal description to the returned error. Must be called in user
* callbacks right before returning the errno.
*
* Note: `HPE_USER` error code might be useful in user callbacks.
*/
LLHTTP_EXPORT
void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
/* Returns the pointer to the last parsed byte before the returned error. The
* pointer is relative to the `data` argument of `llhttp_execute()`.
*
* Note: this method might be useful for counting the number of parsed bytes.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_pos(const llhttp_t* parser);
/* Returns textual name of error code */
LLHTTP_EXPORT
const char* llhttp_errno_name(llhttp_errno_t err);
/* Returns textual name of HTTP method */
LLHTTP_EXPORT
const char* llhttp_method_name(llhttp_method_t method);
/* Enables/disables lenient header value parsing (disabled by default).
*
* Lenient parsing disables header value token checks, extending llhttp's
* protocol support to highly non-compliant clients/server. No
* `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
* lenient parsing is "on".
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and
* `Content-Length` headers (disabled by default).
*
* Normally `llhttp` would error when `Transfer-Encoding` is present in
* conjunction with `Content-Length`. This error is important to prevent HTTP
* request smuggling, but may be less desirable for small number of cases
* involving legacy servers.
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0
* requests responses.
*
* Normally `llhttp` would error on (in strict mode) or discard (in loose mode)
* the HTTP request/response after the request/response with `Connection: close`
* and `Content-Length`. This is important to prevent cache poisoning attacks,
* but might interact badly with outdated and insecure clients. With this flag
* the extra request/response will be parsed normally.
*
* **(USE AT YOUR OWN RISK)**
*/
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_API_H_ */
#endif /* INCLUDE_LLHTTP_H_ */

View File

@@ -23,6 +23,7 @@
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
//#define DUMP_KEI_IV
struct mirror_buffer_s {
@@ -52,8 +53,8 @@ mirror_buffer_init_aes(mirror_buffer_t *mirror_buffer, uint64_t streamConnection
char* siv = "AirPlayStreamIV";
unsigned char skeyall[255];
unsigned char sivall[255];
sprintf((char*) skeyall, "%s%llu", skey, streamConnectionID);
sprintf((char*) sivall, "%s%llu", siv, streamConnectionID);
sprintf((char*) skeyall, "%s%" PRIu64, skey, streamConnectionID);
sprintf((char*) sivall, "%s%" PRIu64, siv, streamConnectionID);
sha_reset(ctx);
sha_update(ctx, skeyall, strlen((char*) skeyall));
sha_update(ctx, eaeskey, 16);

View File

@@ -1,5 +1,6 @@
/**
* Copyright (C) 2018 Juho Vähä-Herttua
* Copyright (C) 2020 Jaslo Ziska
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,17 +17,16 @@
#include <string.h>
#include <assert.h>
#include <openssl/sha.h> // for SHA512_DIGEST_LENGTH
#include "pairing.h"
#include "curve25519/curve25519.h"
#include "ed25519/ed25519.h"
#include "crypto.h"
#define SALT_KEY "Pair-Verify-AES-Key"
#define SALT_IV "Pair-Verify-AES-IV"
struct pairing_s {
unsigned char ed_private[64];
unsigned char ed_public[32];
ed25519_key_t *ed;
};
typedef enum {
@@ -39,19 +39,18 @@ typedef enum {
struct pairing_session_s {
status_t status;
unsigned char ed_private[64];
unsigned char ed_ours[32];
unsigned char ed_theirs[32];
ed25519_key_t *ed_ours;
ed25519_key_t *ed_theirs;
unsigned char ecdh_ours[32];
unsigned char ecdh_theirs[32];
unsigned char ecdh_secret[32];
x25519_key_t *ecdh_ours;
x25519_key_t *ecdh_theirs;
unsigned char ecdh_secret[X25519_KEY_SIZE];
};
static int
derive_key_internal(pairing_session_t *session, const unsigned char *salt, unsigned int saltlen, unsigned char *key, unsigned int keylen)
{
unsigned char hash[64];
unsigned char hash[SHA512_DIGEST_LENGTH];
if (keylen > sizeof(hash)) {
return -1;
@@ -59,7 +58,7 @@ derive_key_internal(pairing_session_t *session, const unsigned char *salt, unsig
sha_ctx_t *ctx = sha_init();
sha_update(ctx, salt, saltlen);
sha_update(ctx, session->ecdh_secret, 32);
sha_update(ctx, session->ecdh_secret, X25519_KEY_SIZE);
sha_final(ctx, hash, NULL);
sha_destroy(ctx);
@@ -69,17 +68,6 @@ derive_key_internal(pairing_session_t *session, const unsigned char *salt, unsig
pairing_t *
pairing_init_generate()
{
unsigned char seed[32];
if (ed25519_create_seed(seed)) {
return NULL;
}
return pairing_init_seed(seed);
}
pairing_t *
pairing_init_seed(const unsigned char seed[32])
{
pairing_t *pairing;
@@ -88,23 +76,23 @@ pairing_init_seed(const unsigned char seed[32])
return NULL;
}
ed25519_create_keypair(pairing->ed_public, pairing->ed_private, seed);
pairing->ed = ed25519_key_generate();
return pairing;
}
void
pairing_get_public_key(pairing_t *pairing, unsigned char public_key[32])
pairing_get_public_key(pairing_t *pairing, unsigned char public_key[ED25519_KEY_SIZE])
{
assert(pairing);
memcpy(public_key, pairing->ed_public, 32);
ed25519_key_get_raw(public_key, pairing->ed);
}
void
pairing_get_ecdh_secret_key(pairing_session_t *session, unsigned char ecdh_secret[32])
pairing_get_ecdh_secret_key(pairing_session_t *session, unsigned char ecdh_secret[X25519_KEY_SIZE])
{
assert(session);
memcpy(ecdh_secret, session->ecdh_secret, 32);
memcpy(ecdh_secret, session->ecdh_secret, X25519_KEY_SIZE);
}
@@ -121,8 +109,9 @@ pairing_session_init(pairing_t *pairing)
if (!session) {
return NULL;
}
memcpy(session->ed_private, pairing->ed_private, 64);
memcpy(session->ed_ours, pairing->ed_public, 32);
session->ed_ours = ed25519_key_copy(pairing->ed);
session->status = STATUS_INITIAL;
return session;
@@ -146,30 +135,28 @@ pairing_session_check_handshake_status(pairing_session_t *session)
}
int
pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[32], const unsigned char ed_key[32])
pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[X25519_KEY_SIZE],
const unsigned char ed_key[ED25519_KEY_SIZE])
{
unsigned char ecdh_priv[32];
assert(session);
if (session->status == STATUS_FINISHED) {
return -1;
}
if (ed25519_create_seed(ecdh_priv)) {
return -2;
}
memcpy(session->ecdh_theirs, ecdh_key, 32);
memcpy(session->ed_theirs, ed_key, 32);
curve25519_donna(session->ecdh_ours, ecdh_priv, kCurve25519BasePoint);
curve25519_donna(session->ecdh_secret, ecdh_priv, session->ecdh_theirs);
session->ecdh_theirs = x25519_key_from_raw(ecdh_key);
session->ed_theirs = ed25519_key_from_raw(ed_key);
session->ecdh_ours = x25519_key_generate();
x25519_derive_secret(session->ecdh_secret, session->ecdh_ours, session->ecdh_theirs);
session->status = STATUS_HANDSHAKE;
return 0;
}
int
pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[32])
pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[X25519_KEY_SIZE])
{
assert(session);
@@ -177,16 +164,17 @@ pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_ke
return -1;
}
memcpy(ecdh_key, session->ecdh_ours, 32);
x25519_key_get_raw(ecdh_key, session->ecdh_ours);
return 0;
}
int
pairing_session_get_signature(pairing_session_t *session, unsigned char signature[64])
pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE])
{
unsigned char sig_msg[64];
unsigned char key[16];
unsigned char iv[16];
unsigned char sig_msg[PAIRING_SIG_SIZE];
unsigned char key[AES_128_BLOCK_SIZE];
unsigned char iv[AES_128_BLOCK_SIZE];
aes_ctx_t *aes_ctx;
assert(session);
@@ -196,29 +184,29 @@ pairing_session_get_signature(pairing_session_t *session, unsigned char signatur
}
/* First sign the public ECDH keys of both parties */
memcpy(&sig_msg[0], session->ecdh_ours, 32);
memcpy(&sig_msg[32], session->ecdh_theirs, 32);
x25519_key_get_raw(sig_msg, session->ecdh_ours);
x25519_key_get_raw(sig_msg + X25519_KEY_SIZE, session->ecdh_theirs);
ed25519_sign(signature, sig_msg, sizeof(sig_msg), session->ed_ours, session->ed_private);
ed25519_sign(signature, PAIRING_SIG_SIZE, sig_msg, PAIRING_SIG_SIZE, session->ed_ours);
/* Then encrypt the result with keys derived from the shared secret */
derive_key_internal(session, (const unsigned char *) SALT_KEY, strlen(SALT_KEY), key, sizeof(key));
derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(key));
derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(iv));
aes_ctx = aes_ctr_init(key, iv);
aes_ctr_encrypt(aes_ctx, signature, signature, 64);
aes_ctr_encrypt(aes_ctx, signature, signature, PAIRING_SIG_SIZE);
aes_ctr_destroy(aes_ctx);
return 0;
}
int
pairing_session_finish(pairing_session_t *session, const unsigned char signature[64])
pairing_session_finish(pairing_session_t *session, const unsigned char signature[PAIRING_SIG_SIZE])
{
unsigned char sig_buffer[64];
unsigned char sig_msg[64];
unsigned char key[16];
unsigned char iv[16];
unsigned char sig_buffer[PAIRING_SIG_SIZE];
unsigned char sig_msg[PAIRING_SIG_SIZE];
unsigned char key[AES_128_BLOCK_SIZE];
unsigned char iv[AES_128_BLOCK_SIZE];
aes_ctx_t *aes_ctx;
assert(session);
@@ -229,18 +217,19 @@ pairing_session_finish(pairing_session_t *session, const unsigned char signature
/* First decrypt the signature with keys derived from the shared secret */
derive_key_internal(session, (const unsigned char *) SALT_KEY, strlen(SALT_KEY), key, sizeof(key));
derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(key));
derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(iv));
aes_ctx = aes_ctr_init(key, iv);
/* One fake round for the initial handshake encryption */
aes_ctr_encrypt(aes_ctx, sig_buffer, sig_buffer, 64);
aes_ctr_encrypt(aes_ctx, signature, sig_buffer, 64);
aes_ctr_encrypt(aes_ctx, sig_buffer, sig_buffer, PAIRING_SIG_SIZE);
aes_ctr_encrypt(aes_ctx, signature, sig_buffer, PAIRING_SIG_SIZE);
aes_ctr_destroy(aes_ctx);
/* Then verify the signature with public ECDH keys of both parties */
memcpy(&sig_msg[0], session->ecdh_theirs, 32);
memcpy(&sig_msg[32], session->ecdh_ours, 32);
if (!ed25519_verify(sig_buffer, sig_msg, sizeof(sig_msg), session->ed_theirs)) {
x25519_key_get_raw(sig_msg, session->ecdh_theirs);
x25519_key_get_raw(sig_msg + X25519_KEY_SIZE, session->ecdh_ours);
if (!ed25519_verify(sig_buffer, PAIRING_SIG_SIZE, sig_msg, PAIRING_SIG_SIZE, session->ed_theirs)) {
return -2;
}
@@ -251,11 +240,22 @@ pairing_session_finish(pairing_session_t *session, const unsigned char signature
void
pairing_session_destroy(pairing_session_t *session)
{
free(session);
if (session) {
ed25519_key_destroy(session->ed_ours);
ed25519_key_destroy(session->ed_theirs);
x25519_key_destroy(session->ecdh_ours);
x25519_key_destroy(session->ecdh_theirs);
free(session);
}
}
void
pairing_destroy(pairing_t *pairing)
{
free(pairing);
if (pairing) {
ed25519_key_destroy(pairing->ed);
free(pairing);
}
}

View File

@@ -1,5 +1,6 @@
/**
* Copyright (C) 2018 Juho Vähä-Herttua
* Copyright (C) 2020 Jaslo Ziska
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -12,27 +13,31 @@
* Lesser General Public License for more details.
*/
#include "crypto.h"
#ifndef PAIRING_H
#define PAIRING_H
#define PAIRING_SIG_SIZE (2 * X25519_KEY_SIZE)
typedef struct pairing_s pairing_t;
typedef struct pairing_session_s pairing_session_t;
pairing_t *pairing_init_generate();
pairing_t *pairing_init_seed(const unsigned char seed[32]);
void pairing_get_public_key(pairing_t *pairing, unsigned char public_key[32]);
void pairing_get_public_key(pairing_t *pairing, unsigned char public_key[ED25519_KEY_SIZE]);
pairing_session_t *pairing_session_init(pairing_t *pairing);
void pairing_session_set_setup_status(pairing_session_t *session);
int pairing_session_check_handshake_status(pairing_session_t *session);
int pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[32], const unsigned char ed_key[32]);
int pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[32]);
int pairing_session_get_signature(pairing_session_t *session, unsigned char signature[64]);
int pairing_session_finish(pairing_session_t *session, const unsigned char signature[64]);
int pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[X25519_KEY_SIZE],
const unsigned char ed_key[ED25519_KEY_SIZE]);
int pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[X25519_KEY_SIZE]);
int pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE]);
int pairing_session_finish(pairing_session_t *session, const unsigned char signature[PAIRING_SIG_SIZE]);
void pairing_session_destroy(pairing_session_t *session);
void pairing_destroy(pairing_t *pairing);
void pairing_get_ecdh_secret_key(pairing_session_t *session, unsigned char ecdh_secret[32]);
void pairing_get_ecdh_secret_key(pairing_session_t *session, unsigned char ecdh_secret[X25519_KEY_SIZE]);
#endif

View File

@@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. plist_src)
set(DIR_SRCS ${plist_src})
add_library( plist
STATIC
${DIR_SRCS})

View File

@@ -1,119 +0,0 @@
/*
* base64.c
* base64 encode/decode implementation
*
* Copyright (c) 2011 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "base64.h"
static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char base64_pad = '=';
static const signed char base64_table[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
size_t base64encode(char *outbuf, const unsigned char *buf, size_t size)
{
if (!outbuf || !buf || (size <= 0)) {
return 0;
}
size_t n = 0;
size_t m = 0;
unsigned char input[3];
unsigned int output[4];
while (n < size) {
input[0] = buf[n];
input[1] = (n+1 < size) ? buf[n+1] : 0;
input[2] = (n+2 < size) ? buf[n+2] : 0;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 3) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 15) << 2) + (input[2] >> 6);
output[3] = input[2] & 63;
outbuf[m++] = base64_str[(int)output[0]];
outbuf[m++] = base64_str[(int)output[1]];
outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad;
outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad;
n+=3;
}
outbuf[m] = 0; // 0-termination!
return m;
}
unsigned char *base64decode(const char *buf, size_t *size)
{
if (!buf || !size) return NULL;
size_t len = (*size > 0) ? *size : strlen(buf);
if (len <= 0) return NULL;
unsigned char *outbuf = (unsigned char*)malloc((len/4)*3+3);
const char *ptr = buf;
int p = 0;
int wv, w1, w2, w3, w4;
int tmpval[4];
int tmpcnt = 0;
do {
while (ptr < buf+len && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n' || *ptr == '\r')) {
ptr++;
}
if (*ptr == '\0' || ptr >= buf+len) {
break;
}
if ((wv = base64_table[(int)(unsigned char)*ptr++]) == -1) {
continue;
}
tmpval[tmpcnt++] = wv;
if (tmpcnt == 4) {
tmpcnt = 0;
w1 = tmpval[0];
w2 = tmpval[1];
w3 = tmpval[2];
w4 = tmpval[3];
if (w1 >= 0 && w2 >= 0) {
outbuf[p++] = (unsigned char)(((w1 << 2) + (w2 >> 4)) & 0xFF);
}
if (w2 >= 0 && w3 >= 0) {
outbuf[p++] = (unsigned char)(((w2 << 4) + (w3 >> 2)) & 0xFF);
}
if (w3 >= 0 && w4 >= 0) {
outbuf[p++] = (unsigned char)(((w3 << 6) + w4) & 0xFF);
}
}
} while (1);
outbuf[p] = 0;
*size = p;
return outbuf;
}

View File

@@ -1,28 +0,0 @@
/*
* base64.h
* base64 encode/decode implementation
*
* Copyright (c) 2011 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BASE64_H
#define BASE64_H
#include <stdlib.h>
size_t base64encode(char *outbuf, const unsigned char *buf, size_t size);
unsigned char *base64decode(const char *buf, size_t *size);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +0,0 @@
/*
* bytearray.c
* simple byte array implementation
*
* Copyright (c) 2011 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "bytearray.h"
#define PAGE_SIZE 4096
bytearray_t *byte_array_new(size_t initial)
{
bytearray_t *a = (bytearray_t*)malloc(sizeof(bytearray_t));
a->capacity = (initial > PAGE_SIZE) ? (initial+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
a->data = malloc(a->capacity);
a->len = 0;
return a;
}
void byte_array_free(bytearray_t *ba)
{
if (!ba) return;
if (ba->data) {
free(ba->data);
}
free(ba);
}
void byte_array_grow(bytearray_t *ba, size_t amount)
{
size_t increase = (amount > PAGE_SIZE) ? (amount+(PAGE_SIZE-1)) & (~(PAGE_SIZE-1)) : PAGE_SIZE;
ba->data = realloc(ba->data, ba->capacity + increase);
ba->capacity += increase;
}
void byte_array_append(bytearray_t *ba, void *buf, size_t len)
{
if (!ba || !ba->data || (len <= 0)) return;
size_t remaining = ba->capacity-ba->len;
if (len > remaining) {
size_t needed = len - remaining;
byte_array_grow(ba, needed);
}
memcpy(((char*)ba->data) + ba->len, buf, len);
ba->len += len;
}

View File

@@ -1,36 +0,0 @@
/*
* bytearray.h
* header file for simple byte array implementation
*
* Copyright (c) 2011 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BYTEARRAY_H
#define BYTEARRAY_H
#include <stdlib.h>
typedef struct bytearray_t {
void *data;
size_t len;
size_t capacity;
} bytearray_t;
bytearray_t *byte_array_new(size_t initial);
void byte_array_free(bytearray_t *ba);
void byte_array_grow(bytearray_t *ba, size_t amount);
void byte_array_append(bytearray_t *ba, void *buf, size_t len);
#endif

View File

@@ -1,46 +0,0 @@
/*
* cnary.c
*
* Created on: Mar 9, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include "node.h"
int main(int argc, char* argv[]) {
puts("Creating root node");
node_t* root = node_create(NULL, NULL);
puts("Creating child 1 node");
node_t* one = node_create(root, NULL);
puts("Creating child 2 node");
node_t* two = node_create(root, NULL);
puts("Creating child 3 node");
node_t* three = node_create(one, NULL);
puts("Debugging root node");
node_debug(root);
puts("Destroying root node");
node_destroy(root);
return 0;
}

View File

@@ -1,140 +0,0 @@
/*
* hashtable.c
* really simple hash table implementation
*
* Copyright (c) 2011-2016 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hashtable.h"
hashtable_t* hash_table_new(hash_func_t hash_func, compare_func_t compare_func, free_func_t free_func)
{
hashtable_t* ht = (hashtable_t*)malloc(sizeof(hashtable_t));
int i;
for (i = 0; i < 4096; i++) {
ht->entries[i] = NULL;
}
ht->count = 0;
ht->hash_func = hash_func;
ht->compare_func = compare_func;
ht->free_func = free_func;
return ht;
}
void hash_table_destroy(hashtable_t *ht)
{
if (!ht) return;
int i = 0;
for (i = 0; i < 4096; i++) {
if (ht->entries[i]) {
hashentry_t* e = ht->entries[i];
while (e) {
if (ht->free_func) {
ht->free_func(e->value);
}
hashentry_t* old = e;
e = e->next;
free(old);
}
}
}
free(ht);
}
void hash_table_insert(hashtable_t* ht, void *key, void *value)
{
if (!ht || !key) return;
unsigned int hash = ht->hash_func(key);
int idx0 = hash & 0xFFF;
// get the idx0 list
hashentry_t* e = ht->entries[idx0];
while (e) {
if (ht->compare_func(e->key, key)) {
// element already present. replace value.
e->value = value;
return;
}
e = e->next;
}
// if we get here, the element is not yet in the list.
// make a new entry.
hashentry_t* entry = (hashentry_t*)malloc(sizeof(hashentry_t));
entry->key = key;
entry->value = value;
if (!ht->entries[idx0]) {
// first entry
entry->next = NULL;
} else {
// add to list
entry->next = ht->entries[idx0];
}
ht->entries[idx0] = entry;
ht->count++;
}
void* hash_table_lookup(hashtable_t* ht, void *key)
{
if (!ht || !key) return NULL;
unsigned int hash = ht->hash_func(key);
int idx0 = hash & 0xFFF;
hashentry_t* e = ht->entries[idx0];
while (e) {
if (ht->compare_func(e->key, key)) {
return e->value;
}
e = e->next;
}
return NULL;
}
void hash_table_remove(hashtable_t* ht, void *key)
{
if (!ht || !key) return;
unsigned int hash = ht->hash_func(key);
int idx0 = hash & 0xFFF;
// get the idx0 list
hashentry_t* e = ht->entries[idx0];
hashentry_t* last = e;
while (e) {
if (ht->compare_func(e->key, key)) {
// found element, remove it from the list
hashentry_t* old = e;
if (e == ht->entries[idx0]) {
ht->entries[idx0] = e->next;
} else {
last->next = e->next;
}
if (ht->free_func) {
ht->free_func(old->value);
}
free(old);
return;
}
last = e;
e = e->next;
}
}

View File

@@ -1,50 +0,0 @@
/*
* hashtable.h
* header file for really simple hash table implementation
*
* Copyright (c) 2011-2016 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <stdlib.h>
typedef struct hashentry_t {
void *key;
void *value;
void *next;
} hashentry_t;
typedef unsigned int(*hash_func_t)(const void* key);
typedef int (*compare_func_t)(const void *a, const void *b);
typedef void (*free_func_t)(void *ptr);
typedef struct hashtable_t {
hashentry_t *entries[4096];
size_t count;
hash_func_t hash_func;
compare_func_t compare_func;
free_func_t free_func;
} hashtable_t;
hashtable_t* hash_table_new(hash_func_t hash_func, compare_func_t compare_func, free_func_t free_func);
void hash_table_destroy(hashtable_t *ht);
void hash_table_insert(hashtable_t* ht, void *key, void *value);
void* hash_table_lookup(hashtable_t* ht, void *key);
void hash_table_remove(hashtable_t* ht, void *key);
#endif

View File

@@ -1,47 +0,0 @@
/*
* list.c
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
void list_init(list_t* list) {
list->next = NULL;
list->prev = list;
}
void list_destroy(list_t* list) {
if(list) {
free(list);
}
}
int list_add(list_t* list, object_t* object) {
return -1;
}
int list_remove(list_t* list, object_t* object) {
return -1;
}

View File

@@ -1,40 +0,0 @@
/*
* list.h
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LIST_H_
#define LIST_H_
#include "object.h"
typedef struct list_t {
void* next;
void* prev;
} list_t;
void list_init(struct list_t* list);
void list_destroy(struct list_t* list);
int list_add(struct list_t* list, struct object_t* object);
int list_remove(struct list_t* list, struct object_t* object);
#endif /* LIST_H_ */

View File

@@ -1,216 +0,0 @@
/*
* node.c
*
* Created on: Mar 7, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "node.h"
#include "node_list.h"
void node_destroy(node_t* node) {
if(!node) return;
if (node->children && node->children->count > 0) {
node_t* ch;
while ((ch = node->children->begin)) {
node_list_remove(node->children, ch);
node_destroy(ch);
}
}
node_list_destroy(node->children);
node->children = NULL;
free(node);
}
node_t* node_create(node_t* parent, void* data) {
int error = 0;
node_t* node = (node_t*) malloc(sizeof(node_t));
if(node == NULL) {
return NULL;
}
memset(node, '\0', sizeof(node_t));
node->data = data;
node->next = NULL;
node->prev = NULL;
node->count = 0;
node->parent = NULL;
node->children = NULL;
// Pass NULL to create a root node
if(parent != NULL) {
// This is a child node so attach it to it's parent
error = node_attach(parent, node);
if(error < 0) {
// Unable to attach nodes
printf("ERROR: %d \"Unable to attach nodes\"\n", error);
node_destroy(node);
return NULL;
}
}
return node;
}
int node_attach(node_t* parent, node_t* child) {
if (!parent || !child) return -1;
child->parent = parent;
if(!parent->children) {
parent->children = node_list_create();
}
int res = node_list_add(parent->children, child);
if (res == 0) {
parent->count++;
}
return res;
}
int node_detach(node_t* parent, node_t* child) {
if (!parent || !child) return -1;
int node_index = node_list_remove(parent->children, child);
if (node_index >= 0) {
parent->count--;
}
return node_index;
}
int node_insert(node_t* parent, unsigned int node_index, node_t* child)
{
if (!parent || !child) return -1;
child->parent = parent;
if(!parent->children) {
parent->children = node_list_create();
}
int res = node_list_insert(parent->children, node_index, child);
if (res == 0) {
parent->count++;
}
return res;
}
static void _node_debug(node_t* node, unsigned int depth) {
unsigned int i = 0;
node_t* current = NULL;
for(i = 0; i < depth; i++) {
printf("\t");
}
if(!node->parent) {
printf("ROOT\n");
}
if(!node->children && node->parent) {
printf("LEAF\n");
} else {
if(node->parent) {
printf("NODE\n");
}
for (current = node_first_child(node); current; current = node_next_sibling(current)) {
_node_debug(current, depth+1);
}
}
}
void node_debug(node_t* node)
{
_node_debug(node, 0);
}
unsigned int node_n_children(struct node_t* node)
{
if (!node) return 0;
return node->count;
}
node_t* node_nth_child(struct node_t* node, unsigned int n)
{
if (!node || !node->children || !node->children->begin) return NULL;
unsigned int node_index = 0;
int found = 0;
node_t *ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
if (node_index++ == n) {
found = 1;
break;
}
}
if (!found) {
return NULL;
}
return ch;
}
node_t* node_first_child(struct node_t* node)
{
if (!node || !node->children) return NULL;
return node->children->begin;
}
node_t* node_prev_sibling(struct node_t* node)
{
if (!node) return NULL;
return node->prev;
}
node_t* node_next_sibling(struct node_t* node)
{
if (!node) return NULL;
return node->next;
}
int node_child_position(struct node_t* parent, node_t* child)
{
if (!parent || !parent->children || !parent->children->begin || !child) return -1;
int node_index = 0;
int found = 0;
node_t *ch;
for (ch = node_first_child(parent); ch; ch = node_next_sibling(ch)) {
if (ch == child) {
found = 1;
break;
}
node_index++;
}
if (!found) {
return -1;
}
return node_index;
}
node_t* node_copy_deep(node_t* node, copy_func_t copy_func)
{
if (!node) return NULL;
void *data = NULL;
if (copy_func) {
data = copy_func(node->data);
}
node_t* copy = node_create(NULL, data);
node_t* ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
node_t* cc = node_copy_deep(ch, copy_func);
node_attach(copy, cc);
}
return copy;
}

View File

@@ -1,65 +0,0 @@
/*
* node.h
*
* Created on: Mar 7, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NODE_H_
#define NODE_H_
#include "object.h"
#define NODE_TYPE 1;
struct node_list_t;
// This class implements the abstract iterator class
typedef struct node_t {
// Super class
struct node_t* next;
struct node_t* prev;
unsigned int count;
// Local Members
void *data;
struct node_t* parent;
struct node_list_t* children;
} node_t;
void node_destroy(struct node_t* node);
struct node_t* node_create(struct node_t* parent, void* data);
int node_attach(struct node_t* parent, struct node_t* child);
int node_detach(struct node_t* parent, struct node_t* child);
int node_insert(struct node_t* parent, unsigned int index, struct node_t* child);
unsigned int node_n_children(struct node_t* node);
node_t* node_nth_child(struct node_t* node, unsigned int n);
node_t* node_first_child(struct node_t* node);
node_t* node_prev_sibling(struct node_t* node);
node_t* node_next_sibling(struct node_t* node);
int node_child_position(struct node_t* parent, node_t* child);
typedef void* (*copy_func_t)(const void *src);
node_t* node_copy_deep(node_t* node, copy_func_t copy_func);
void node_debug(struct node_t* node);
#endif /* NODE_H_ */

View File

@@ -1,154 +0,0 @@
/*
* node_list.c
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "node.h"
#include "node_list.h"
void node_list_destroy(node_list_t* list) {
if(list != NULL) {
list_destroy((list_t*) list);
}
}
node_list_t* node_list_create() {
node_list_t* list = (node_list_t*) malloc(sizeof(node_list_t));
if(list == NULL) {
return NULL;
}
memset(list, '\0', sizeof(node_list_t));
// Initialize structure
list_init((list_t*) list);
list->count = 0;
return list;
}
int node_list_add(node_list_t* list, node_t* node) {
if (!list || !node) return -1;
// Find the last element in the list
node_t* last = list->end;
// Setup our new node as the new last element
node->next = NULL;
node->prev = last;
// Set the next element of our old "last" element
if (last) {
// but only if the node list is not empty
last->next = node;
}
// Set the lists prev to the new last element
list->end = node;
// Increment our node count for this list
list->count++;
return 0;
}
int node_list_insert(node_list_t* list, unsigned int node_index, node_t* node) {
if (!list || !node) return -1;
if (node_index >= list->count) {
return node_list_add(list, node);
}
// Get the first element in the list
node_t* cur = list->begin;
unsigned int pos = 0;
node_t* prev = NULL;
if (node_index > 0) {
while (pos < node_index) {
prev = cur;
cur = cur->next;
pos++;
}
}
if (prev) {
// Set previous node
node->prev = prev;
// Set next node of our new node to next node of the previous node
node->next = prev->next;
// Set next node of previous node to our new node
prev->next = node;
} else {
node->prev = NULL;
// get old first element in list
node->next = list->begin;
// set new node as first element in list
list->begin = node;
}
if (node->next == NULL) {
// Set the lists prev to the new last element
list->end = node;
} else {
// set prev of the new next element to our node
node->next->prev = node;
}
// Increment our node count for this list
list->count++;
return 0;
}
int node_list_remove(node_list_t* list, node_t* node) {
if (!list || !node) return -1;
if (list->count == 0) return -1;
int node_index = 0;
node_t* n;
for (n = list->begin; n; n = n->next) {
if (node == n) {
node_t* newnode = node->next;
if (node->prev) {
node->prev->next = newnode;
if (newnode) {
newnode->prev = node->prev;
} else {
// last element in the list
list->end = node->prev;
}
} else {
// we just removed the first element
if (newnode) {
newnode->prev = NULL;
}
list->begin = newnode;
}
list->count--;
return node_index;
}
node_index++;
}
return -1;
}

View File

@@ -1,47 +0,0 @@
/*
* node_list.h
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NODE_LIST_H_
#define NODE_LIST_H_
struct node_t;
// This class implements the list_t abstract class
typedef struct node_list_t {
// list_t members
struct node_t* begin;
struct node_t* end;
// node_list_t members
unsigned int count;
} node_list_t;
void node_list_destroy(struct node_list_t* list);
struct node_list_t* node_list_create();
int node_list_add(node_list_t* list, node_t* node);
int node_list_insert(node_list_t* list, unsigned int index, node_t* node);
int node_list_remove(node_list_t* list, node_t* node);
#endif /* NODE_LIST_H_ */

View File

@@ -1,41 +0,0 @@
/*
* object.h
*
* Created on: Mar 8, 2011
* Author: posixninja
*
* Copyright (c) 2011 Joshua Hill. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef OBJECT_H_
#define OBJECT_H_
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef struct object_t {
void* value;
unsigned int type;
unsigned int size;
} object_t;
#endif /* OBJECT_H_ */

View File

@@ -1,963 +0,0 @@
/*
* plist.c
* Builds plist XML structures
*
* Copyright (c) 2009-2016 Nikias Bassen All Rights Reserved.
* Copyright (c) 2010-2015 Martin Szulecki All Rights Reserved.
* Copyright (c) 2008 Zach C. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <assert.h>
#include "plist.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "node.h"
#include "hashtable.h"
extern void plist_xml_init(void);
extern void plist_xml_deinit(void);
extern void plist_bin_init(void);
extern void plist_bin_deinit(void);
static void internal_plist_init(void)
{
plist_bin_init();
plist_xml_init();
}
static void internal_plist_deinit(void)
{
plist_bin_deinit();
plist_xml_deinit();
}
#ifdef WIN32
typedef volatile struct {
LONG lock;
int state;
} thread_once_t;
static thread_once_t init_once = {0, 0};
static thread_once_t deinit_once = {0, 0};
void thread_once(thread_once_t *once_control, void (*init_routine)(void))
{
while (InterlockedExchange(&(once_control->lock), 1) != 0) {
Sleep(1);
}
if (!once_control->state) {
once_control->state = 1;
init_routine();
}
InterlockedExchange(&(once_control->lock), 0);
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason) {
case DLL_PROCESS_ATTACH:
thread_once(&init_once, internal_plist_init);
break;
case DLL_PROCESS_DETACH:
thread_once(&deinit_once, internal_plist_deinit);
break;
default:
break;
}
return 1;
}
#else
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
static pthread_once_t deinit_once = PTHREAD_ONCE_INIT;
static void __attribute__((constructor)) libplist_initialize(void)
{
pthread_once(&init_once, internal_plist_init);
}
static void __attribute__((destructor)) libplist_deinitialize(void)
{
pthread_once(&deinit_once, internal_plist_deinit);
}
#endif
PLIST_API int plist_is_binary(const char *plist_data, uint32_t length)
{
if (length < 8) {
return 0;
}
return (memcmp(plist_data, "bplist00", 8) == 0);
}
PLIST_API void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist)
{
if (length < 8) {
*plist = NULL;
return;
}
if (plist_is_binary(plist_data, length)) {
plist_from_bin(plist_data, length, plist);
} else {
plist_from_xml(plist_data, length, plist);
}
}
plist_t plist_new_node(plist_data_t data)
{
return (plist_t) node_create(NULL, data);
}
plist_data_t plist_get_data(const plist_t node)
{
if (!node)
return NULL;
return ((node_t*)node)->data;
}
plist_data_t plist_new_plist_data(void)
{
plist_data_t data = (plist_data_t) calloc(sizeof(struct plist_data_s), 1);
return data;
}
static unsigned int dict_key_hash(const void *data)
{
plist_data_t keydata = (plist_data_t)data;
unsigned int hash = 5381;
size_t i;
char *str = keydata->strval;
for (i = 0; i < keydata->length; str++, i++) {
hash = ((hash << 5) + hash) + *str;
}
return hash;
}
static int dict_key_compare(const void* a, const void* b)
{
plist_data_t data_a = (plist_data_t)a;
plist_data_t data_b = (plist_data_t)b;
if (data_a->strval == NULL || data_b->strval == NULL) {
return FALSE;
}
if (data_a->length != data_b->length) {
return FALSE;
}
return (strcmp(data_a->strval, data_b->strval) == 0) ? TRUE : FALSE;
}
void plist_free_data(plist_data_t data)
{
if (data)
{
switch (data->type)
{
case PLIST_KEY:
case PLIST_STRING:
free(data->strval);
break;
case PLIST_DATA:
free(data->buff);
break;
case PLIST_DICT:
hash_table_destroy(data->hashtable);
break;
default:
break;
}
free(data);
}
}
static int plist_free_node(node_t* node)
{
plist_data_t data = NULL;
int node_index = node_detach(node->parent, node);
data = plist_get_data(node);
plist_free_data(data);
node->data = NULL;
node_t *ch;
for (ch = node_first_child(node); ch; ) {
node_t *next = node_next_sibling(ch);
plist_free_node(ch);
ch = next;
}
node_destroy(node);
return node_index;
}
PLIST_API plist_t plist_new_dict(void)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DICT;
return plist_new_node(data);
}
PLIST_API plist_t plist_new_array(void)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_ARRAY;
return plist_new_node(data);
}
//These nodes should not be handled by users
static plist_t plist_new_key(const char *val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_KEY;
data->strval = strdup(val);
data->length = strlen(val);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_string(const char *val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_STRING;
data->strval = strdup(val);
data->length = strlen(val);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_bool(uint8_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_BOOLEAN;
data->boolval = val;
data->length = sizeof(uint8_t);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_uint(uint64_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_UINT;
data->intval = val;
data->length = sizeof(uint64_t);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_uid(uint64_t val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_UID;
data->intval = val;
data->length = sizeof(uint64_t);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_real(double val)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_REAL;
data->realval = val;
data->length = sizeof(double);
return plist_new_node(data);
}
PLIST_API plist_t plist_new_data(const char *val, uint64_t length)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATA;
data->buff = (uint8_t *) malloc(length);
memcpy(data->buff, val, length);
data->length = length;
return plist_new_node(data);
}
PLIST_API plist_t plist_new_date(int32_t sec, int32_t usec)
{
plist_data_t data = plist_new_plist_data();
data->type = PLIST_DATE;
data->realval = (double)sec + (double)usec / 1000000;
data->length = sizeof(double);
return plist_new_node(data);
}
PLIST_API void plist_free(plist_t plist)
{
if (plist)
{
plist_free_node(plist);
}
}
static void plist_copy_node(node_t *node, void *parent_node_ptr)
{
plist_type node_type = PLIST_NONE;
plist_t newnode = NULL;
plist_data_t data = plist_get_data(node);
plist_data_t newdata = plist_new_plist_data();
assert(data); // plist should always have data
memcpy(newdata, data, sizeof(struct plist_data_s));
node_type = plist_get_node_type(node);
switch (node_type) {
case PLIST_DATA:
newdata->buff = (uint8_t *) malloc(data->length);
memcpy(newdata->buff, data->buff, data->length);
break;
case PLIST_KEY:
case PLIST_STRING:
newdata->strval = strdup((char *) data->strval);
break;
case PLIST_DICT:
if (data->hashtable) {
hashtable_t* ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
assert(ht);
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
ht && current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
}
newdata->hashtable = ht;
}
break;
default:
break;
}
newnode = plist_new_node(newdata);
if (*(plist_t*)parent_node_ptr)
{
node_attach(*(plist_t*)parent_node_ptr, newnode);
}
else
{
*(plist_t*)parent_node_ptr = newnode;
}
node_t *ch;
for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
plist_copy_node(ch, &newnode);
}
}
PLIST_API plist_t plist_copy(plist_t node)
{
plist_t copied = NULL;
plist_copy_node(node, &copied);
return copied;
}
PLIST_API uint32_t plist_array_get_size(plist_t node)
{
uint32_t ret = 0;
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
ret = node_n_children(node);
}
return ret;
}
PLIST_API plist_t plist_array_get_item(plist_t node, uint32_t n)
{
plist_t ret = NULL;
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
ret = (plist_t)node_nth_child(node, n);
}
return ret;
}
PLIST_API uint32_t plist_array_get_item_index(plist_t node)
{
plist_t father = plist_get_parent(node);
if (PLIST_ARRAY == plist_get_node_type(father))
{
return node_child_position(father, node);
}
return 0;
}
PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
plist_t old_item = plist_array_get_item(node, n);
if (old_item)
{
int idx = plist_free_node(old_item);
if (idx < 0) {
node_attach(node, item);
} else {
node_insert(node, idx, item);
}
}
}
return;
}
PLIST_API void plist_array_append_item(plist_t node, plist_t item)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
node_attach(node, item);
}
return;
}
PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
node_insert(node, n, item);
}
return;
}
PLIST_API void plist_array_remove_item(plist_t node, uint32_t n)
{
if (node && PLIST_ARRAY == plist_get_node_type(node))
{
plist_t old_item = plist_array_get_item(node, n);
if (old_item)
{
plist_free(old_item);
}
}
return;
}
PLIST_API uint32_t plist_dict_get_size(plist_t node)
{
uint32_t ret = 0;
if (node && PLIST_DICT == plist_get_node_type(node))
{
ret = node_n_children(node) / 2;
}
return ret;
}
PLIST_API void plist_dict_new_iter(plist_t node, plist_dict_iter *iter)
{
if (iter && *iter == NULL)
{
*iter = malloc(sizeof(node_t*));
*((node_t**)(*iter)) = node_first_child(node);
}
return;
}
PLIST_API void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val)
{
node_t** iter_node = (node_t**)iter;
if (key)
{
*key = NULL;
}
if (val)
{
*val = NULL;
}
if (node && PLIST_DICT == plist_get_node_type(node) && *iter_node)
{
if (key)
{
plist_get_key_val((plist_t)(*iter_node), key);
}
*iter_node = node_next_sibling(*iter_node);
if (val)
{
*val = (plist_t)(*iter_node);
}
*iter_node = node_next_sibling(*iter_node);
}
return;
}
PLIST_API void plist_dict_get_item_key(plist_t node, char **key)
{
plist_t father = plist_get_parent(node);
if (PLIST_DICT == plist_get_node_type(father))
{
plist_get_key_val( (plist_t) node_prev_sibling(node), key);
}
}
PLIST_API plist_t plist_dict_get_item(plist_t node, const char* key)
{
plist_t ret = NULL;
if (node && PLIST_DICT == plist_get_node_type(node))
{
plist_data_t data = plist_get_data(node);
hashtable_t *ht = (hashtable_t*)data->hashtable;
if (ht) {
struct plist_data_s sdata;
sdata.strval = (char*)key;
sdata.length = strlen(key);
ret = (plist_t)hash_table_lookup(ht, &sdata);
} else {
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
data = plist_get_data(current);
assert( PLIST_KEY == plist_get_node_type(current) );
if (data && !strcmp(key, data->strval))
{
ret = (plist_t)node_next_sibling(current);
break;
}
}
}
}
return ret;
}
PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item)
{
if (node && PLIST_DICT == plist_get_node_type(node)) {
node_t* old_item = plist_dict_get_item(node, key);
plist_t key_node = NULL;
if (old_item) {
int idx = plist_free_node(old_item);
if (idx < 0) {
node_attach(node, item);
} else {
node_insert(node, idx, item);
}
key_node = node_prev_sibling(item);
} else {
key_node = plist_new_key(key);
node_attach(node, key_node);
node_attach(node, item);
}
hashtable_t *ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
if (ht) {
/* store pointer to item in hash table */
hash_table_insert(ht, (plist_data_t)((node_t*)key_node)->data, item);
} else {
if (((node_t*)node)->count > 500) {
/* make new hash table */
ht = hash_table_new(dict_key_hash, dict_key_compare, NULL);
/* calculate the hashes for all entries we have so far */
plist_t current = NULL;
for (current = (plist_t)node_first_child(node);
ht && current;
current = (plist_t)node_next_sibling(node_next_sibling(current)))
{
hash_table_insert(ht, ((node_t*)current)->data, node_next_sibling(current));
}
((plist_data_t)((node_t*)node)->data)->hashtable = ht;
}
}
}
return;
}
PLIST_API void plist_dict_insert_item(plist_t node, const char* key, plist_t item)
{
plist_dict_set_item(node, key, item);
}
PLIST_API void plist_dict_remove_item(plist_t node, const char* key)
{
if (node && PLIST_DICT == plist_get_node_type(node))
{
plist_t old_item = plist_dict_get_item(node, key);
if (old_item)
{
plist_t key_node = node_prev_sibling(old_item);
hashtable_t* ht = ((plist_data_t)((node_t*)node)->data)->hashtable;
if (ht) {
hash_table_remove(ht, ((node_t*)key_node)->data);
}
plist_free(key_node);
plist_free(old_item);
}
}
return;
}
PLIST_API void plist_dict_merge(plist_t *target, plist_t source)
{
if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT))
return;
char* key = NULL;
plist_dict_iter it = NULL;
plist_t subnode = NULL;
plist_dict_new_iter(source, &it);
if (!it)
return;
do {
plist_dict_next_item(source, it, &key, &subnode);
if (!key)
break;
plist_dict_set_item(*target, key, plist_copy(subnode));
free(key);
key = NULL;
} while (1);
free(it);
}
PLIST_API plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v)
{
plist_t current = plist;
plist_type type = PLIST_NONE;
uint32_t i = 0;
for (i = 0; i < length && current; i++)
{
type = plist_get_node_type(current);
if (type == PLIST_ARRAY)
{
uint32_t n = va_arg(v, uint32_t);
current = plist_array_get_item(current, n);
}
else if (type == PLIST_DICT)
{
const char* key = va_arg(v, const char*);
current = plist_dict_get_item(current, key);
}
}
return current;
}
PLIST_API plist_t plist_access_path(plist_t plist, uint32_t length, ...)
{
plist_t ret = NULL;
va_list v;
va_start(v, length);
ret = plist_access_pathv(plist, length, v);
va_end(v);
return ret;
}
static void plist_get_type_and_value(plist_t node, plist_type * type, void *value, uint64_t * length)
{
plist_data_t data = NULL;
if (!node)
return;
data = plist_get_data(node);
*type = data->type;
*length = data->length;
switch (*type)
{
case PLIST_BOOLEAN:
*((char *) value) = data->boolval;
break;
case PLIST_UINT:
case PLIST_UID:
*((uint64_t *) value) = data->intval;
break;
case PLIST_REAL:
case PLIST_DATE:
*((double *) value) = data->realval;
break;
case PLIST_KEY:
case PLIST_STRING:
*((char **) value) = strdup(data->strval);
break;
case PLIST_DATA:
*((uint8_t **) value) = (uint8_t *) malloc(*length * sizeof(uint8_t));
memcpy(*((uint8_t **) value), data->buff, *length * sizeof(uint8_t));
break;
case PLIST_ARRAY:
case PLIST_DICT:
default:
break;
}
}
PLIST_API plist_t plist_get_parent(plist_t node)
{
return node ? (plist_t) ((node_t*) node)->parent : NULL;
}
PLIST_API plist_type plist_get_node_type(plist_t node)
{
if (node)
{
plist_data_t data = plist_get_data(node);
if (data)
return data->type;
}
return PLIST_NONE;
}
PLIST_API void plist_get_key_val(plist_t node, char **val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_KEY == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == strlen(*val));
}
PLIST_API void plist_get_string_val(plist_t node, char **val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_STRING == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == strlen(*val));
}
PLIST_API void plist_get_bool_val(plist_t node, uint8_t * val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_BOOLEAN == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint8_t));
}
PLIST_API void plist_get_uint_val(plist_t node, uint64_t * val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_UINT == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint64_t) || length == 16);
}
PLIST_API void plist_get_uid_val(plist_t node, uint64_t * val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_UID == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(uint64_t));
}
PLIST_API void plist_get_real_val(plist_t node, double *val)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
if (PLIST_REAL == type)
plist_get_type_and_value(node, &type, (void *) val, &length);
assert(length == sizeof(double));
}
PLIST_API void plist_get_data_val(plist_t node, char **val, uint64_t * length)
{
plist_type type = plist_get_node_type(node);
if (PLIST_DATA == type)
plist_get_type_and_value(node, &type, (void *) val, length);
}
PLIST_API void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec)
{
plist_type type = plist_get_node_type(node);
uint64_t length = 0;
double val = 0;
if (PLIST_DATE == type)
plist_get_type_and_value(node, &type, (void *) &val, &length);
assert(length == sizeof(double));
*sec = (int32_t)val;
*usec = (int32_t)fabs((val - (int64_t)val) * 1000000);
}
int plist_data_compare(const void *a, const void *b)
{
plist_data_t val_a = NULL;
plist_data_t val_b = NULL;
if (!a || !b)
return FALSE;
if (!((node_t*) a)->data || !((node_t*) b)->data)
return FALSE;
val_a = plist_get_data((plist_t) a);
val_b = plist_get_data((plist_t) b);
if (val_a->type != val_b->type)
return FALSE;
switch (val_a->type)
{
case PLIST_BOOLEAN:
case PLIST_UINT:
case PLIST_REAL:
case PLIST_DATE:
case PLIST_UID:
if (val_a->length != val_b->length)
return FALSE;
if (val_a->intval == val_b->intval) //it is an union so this is sufficient
return TRUE;
else
return FALSE;
case PLIST_KEY:
case PLIST_STRING:
if (!strcmp(val_a->strval, val_b->strval))
return TRUE;
else
return FALSE;
case PLIST_DATA:
if (val_a->length != val_b->length)
return FALSE;
if (!memcmp(val_a->buff, val_b->buff, val_a->length))
return TRUE;
else
return FALSE;
case PLIST_ARRAY:
case PLIST_DICT:
//compare pointer
if (a == b)
return TRUE;
else
return FALSE;
break;
default:
break;
}
return FALSE;
}
PLIST_API char plist_compare_node_value(plist_t node_l, plist_t node_r)
{
return plist_data_compare(node_l, node_r);
}
static void plist_set_element_val(plist_t node, plist_type type, const void *value, uint64_t length)
{
//free previous allocated buffer
plist_data_t data = plist_get_data(node);
assert(data); // a node should always have data attached
switch (data->type)
{
case PLIST_KEY:
case PLIST_STRING:
free(data->strval);
data->strval = NULL;
break;
case PLIST_DATA:
free(data->buff);
data->buff = NULL;
break;
default:
break;
}
//now handle value
data->type = type;
data->length = length;
switch (type)
{
case PLIST_BOOLEAN:
data->boolval = *((char *) value);
break;
case PLIST_UINT:
case PLIST_UID:
data->intval = *((uint64_t *) value);
break;
case PLIST_REAL:
case PLIST_DATE:
data->realval = *((double *) value);
break;
case PLIST_KEY:
case PLIST_STRING:
data->strval = strdup((char *) value);
break;
case PLIST_DATA:
data->buff = (uint8_t *) malloc(length);
memcpy(data->buff, value, length);
break;
case PLIST_ARRAY:
case PLIST_DICT:
default:
break;
}
}
PLIST_API void plist_set_key_val(plist_t node, const char *val)
{
plist_set_element_val(node, PLIST_KEY, val, strlen(val));
}
PLIST_API void plist_set_string_val(plist_t node, const char *val)
{
plist_set_element_val(node, PLIST_STRING, val, strlen(val));
}
PLIST_API void plist_set_bool_val(plist_t node, uint8_t val)
{
plist_set_element_val(node, PLIST_BOOLEAN, &val, sizeof(uint8_t));
}
PLIST_API void plist_set_uint_val(plist_t node, uint64_t val)
{
plist_set_element_val(node, PLIST_UINT, &val, sizeof(uint64_t));
}
PLIST_API void plist_set_uid_val(plist_t node, uint64_t val)
{
plist_set_element_val(node, PLIST_UID, &val, sizeof(uint64_t));
}
PLIST_API void plist_set_real_val(plist_t node, double val)
{
plist_set_element_val(node, PLIST_REAL, &val, sizeof(double));
}
PLIST_API void plist_set_data_val(plist_t node, const char *val, uint64_t length)
{
plist_set_element_val(node, PLIST_DATA, val, length);
}
PLIST_API void plist_set_date_val(plist_t node, int32_t sec, int32_t usec)
{
double val = (double)sec + (double)usec / 1000000;
plist_set_element_val(node, PLIST_DATE, &val, sizeof(struct timeval));
}

View File

@@ -1,74 +0,0 @@
/*
* plist.h
* contains structures and the like for plists
*
* Copyright (c) 2008 Zach C. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PLIST_H
#define PLIST_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "plist/plist.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef _MSC_VER
#pragma warning(disable:4996)
#pragma warning(disable:4244)
#endif
#ifdef WIN32
#define PLIST_API __declspec( dllexport )
#else
#ifdef HAVE_FVISIBILITY
#define PLIST_API __attribute__((visibility("default")))
#else
#define PLIST_API
#endif
#endif
struct plist_data_s
{
union
{
char boolval;
uint64_t intval;
double realval;
char *strval;
uint8_t *buff;
void *hashtable;
};
uint64_t length;
plist_type type;
};
typedef struct plist_data_s *plist_data_t;
plist_t plist_new_node(plist_data_t data);
plist_data_t plist_get_data(const plist_t node);
plist_data_t plist_new_plist_data(void);
void plist_free_data(plist_data_t data);
int plist_data_compare(const void *a, const void *b);
#endif

View File

@@ -1,686 +0,0 @@
/**
* @file plist/plist.h
* @brief Main include of libplist
* \internal
*
* Copyright (c) 2008 Jonathan Beck All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LIBPLIST_H
#define LIBPLIST_H
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef _MSC_VER
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#ifdef __llvm__
#if defined(__has_extension)
#if (__has_extension(attribute_deprecated_with_message))
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated(x)))
#endif
#else
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated))
#endif
#endif
#else
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated))
#endif
#endif
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 5)))
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __attribute__((deprecated(x)))
#endif
#elif defined(_MSC_VER)
#ifndef PLIST_WARN_DEPRECATED
#define PLIST_WARN_DEPRECATED(x) __declspec(deprecated(x))
#endif
#else
#define PLIST_WARN_DEPRECATED(x)
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#endif
#include <sys/types.h>
#include <stdarg.h>
/**
* \mainpage libplist : A library to handle Apple Property Lists
* \defgroup PublicAPI Public libplist API
*/
/*@{*/
/**
* The basic plist abstract data type.
*/
typedef void *plist_t;
/**
* The plist dictionary iterator.
*/
typedef void *plist_dict_iter;
/**
* The enumeration of plist node types.
*/
typedef enum
{
PLIST_BOOLEAN, /**< Boolean, scalar type */
PLIST_UINT, /**< Unsigned integer, scalar type */
PLIST_REAL, /**< Real, scalar type */
PLIST_STRING, /**< ASCII string, scalar type */
PLIST_ARRAY, /**< Ordered array, structured type */
PLIST_DICT, /**< Unordered dictionary (key/value pair), structured type */
PLIST_DATE, /**< Date, scalar type */
PLIST_DATA, /**< Binary data, scalar type */
PLIST_KEY, /**< Key in dictionaries (ASCII String), scalar type */
PLIST_UID, /**< Special type used for 'keyed encoding' */
PLIST_NONE /**< No type */
} plist_type;
/********************************************
* *
* Creation & Destruction *
* *
********************************************/
/**
* Create a new root plist_t type #PLIST_DICT
*
* @return the created plist
* @sa #plist_type
*/
plist_t plist_new_dict(void);
/**
* Create a new root plist_t type #PLIST_ARRAY
*
* @return the created plist
* @sa #plist_type
*/
plist_t plist_new_array(void);
/**
* Create a new plist_t type #PLIST_STRING
*
* @param val the sting value, encoded in UTF8.
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_string(const char *val);
/**
* Create a new plist_t type #PLIST_BOOLEAN
*
* @param val the boolean value, 0 is false, other values are true.
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_bool(uint8_t val);
/**
* Create a new plist_t type #PLIST_UINT
*
* @param val the unsigned integer value
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_uint(uint64_t val);
/**
* Create a new plist_t type #PLIST_REAL
*
* @param val the real value
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_real(double val);
/**
* Create a new plist_t type #PLIST_DATA
*
* @param val the binary buffer
* @param length the length of the buffer
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_data(const char *val, uint64_t length);
/**
* Create a new plist_t type #PLIST_DATE
*
* @param sec the number of seconds since 01/01/2001
* @param usec the number of microseconds
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_date(int32_t sec, int32_t usec);
/**
* Create a new plist_t type #PLIST_UID
*
* @param val the unsigned integer value
* @return the created item
* @sa #plist_type
*/
plist_t plist_new_uid(uint64_t val);
/**
* Destruct a plist_t node and all its children recursively
*
* @param plist the plist to free
*/
void plist_free(plist_t plist);
/**
* Return a copy of passed node and it's children
*
* @param node the plist to copy
* @return copied plist
*/
plist_t plist_copy(plist_t node);
/********************************************
* *
* Array functions *
* *
********************************************/
/**
* Get size of a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @return size of the #PLIST_ARRAY node
*/
uint32_t plist_array_get_size(plist_t node);
/**
* Get the nth item in a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @param n the index of the item to get. Range is [0, array_size[
* @return the nth item or NULL if node is not of type #PLIST_ARRAY
*/
plist_t plist_array_get_item(plist_t node, uint32_t n);
/**
* Get the index of an item. item must be a member of a #PLIST_ARRAY node.
*
* @param node the node
* @return the node index
*/
uint32_t plist_array_get_item_index(plist_t node);
/**
* Set the nth item in a #PLIST_ARRAY node.
* The previous item at index n will be freed using #plist_free
*
* @param node the node of type #PLIST_ARRAY
* @param item the new item at index n. The array is responsible for freeing item when it is no longer needed.
* @param n the index of the item to get. Range is [0, array_size[. Assert if n is not in range.
*/
void plist_array_set_item(plist_t node, plist_t item, uint32_t n);
/**
* Append a new item at the end of a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @param item the new item. The array is responsible for freeing item when it is no longer needed.
*/
void plist_array_append_item(plist_t node, plist_t item);
/**
* Insert a new item at position n in a #PLIST_ARRAY node.
*
* @param node the node of type #PLIST_ARRAY
* @param item the new item to insert. The array is responsible for freeing item when it is no longer needed.
* @param n The position at which the node will be stored. Range is [0, array_size[. Assert if n is not in range.
*/
void plist_array_insert_item(plist_t node, plist_t item, uint32_t n);
/**
* Remove an existing position in a #PLIST_ARRAY node.
* Removed position will be freed using #plist_free.
*
* @param node the node of type #PLIST_ARRAY
* @param n The position to remove. Range is [0, array_size[. Assert if n is not in range.
*/
void plist_array_remove_item(plist_t node, uint32_t n);
/********************************************
* *
* Dictionary functions *
* *
********************************************/
/**
* Get size of a #PLIST_DICT node.
*
* @param node the node of type #PLIST_DICT
* @return size of the #PLIST_DICT node
*/
uint32_t plist_dict_get_size(plist_t node);
/**
* Create an iterator of a #PLIST_DICT node.
* The allocated iterator should be freed with the standard free function.
*
* @param node the node of type #PLIST_DICT
* @param iter iterator of the #PLIST_DICT node
*/
void plist_dict_new_iter(plist_t node, plist_dict_iter *iter);
/**
* Increment iterator of a #PLIST_DICT node.
*
* @param node the node of type #PLIST_DICT
* @param iter iterator of the dictionary
* @param key a location to store the key, or NULL. The caller is responsible
* for freeing the the returned string.
* @param val a location to store the value, or NULL. The caller should *not*
* free the returned value.
*/
void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val);
/**
* Get key associated to an item. Item must be member of a dictionary
*
* @param node the node
* @param key a location to store the key. The caller is responsible for freeing the returned string.
*/
void plist_dict_get_item_key(plist_t node, char **key);
/**
* Get the nth item in a #PLIST_DICT node.
*
* @param node the node of type #PLIST_DICT
* @param key the identifier of the item to get.
* @return the item or NULL if node is not of type #PLIST_DICT. The caller should not free
* the returned node.
*/
plist_t plist_dict_get_item(plist_t node, const char* key);
/**
* Set item identified by key in a #PLIST_DICT node.
* The previous item identified by key will be freed using #plist_free.
* If there is no item for the given key a new item will be inserted.
*
* @param node the node of type #PLIST_DICT
* @param item the new item associated to key
* @param key the identifier of the item to set.
*/
void plist_dict_set_item(plist_t node, const char* key, plist_t item);
/**
* Insert a new item into a #PLIST_DICT node.
*
* @deprecated Deprecated. Use plist_dict_set_item instead.
*
* @param node the node of type #PLIST_DICT
* @param item the new item to insert
* @param key The identifier of the item to insert.
*/
PLIST_WARN_DEPRECATED("use plist_dict_set_item instead")
void plist_dict_insert_item(plist_t node, const char* key, plist_t item);
/**
* Remove an existing position in a #PLIST_DICT node.
* Removed position will be freed using #plist_free
*
* @param node the node of type #PLIST_DICT
* @param key The identifier of the item to remove. Assert if identifier is not present.
*/
void plist_dict_remove_item(plist_t node, const char* key);
/**
* Merge a dictionary into another. This will add all key/value pairs
* from the source dictionary to the target dictionary, overwriting
* any existing key/value pairs that are already present in target.
*
* @param target pointer to an existing node of type #PLIST_DICT
* @param source node of type #PLIST_DICT that should be merged into target
*/
void plist_dict_merge(plist_t *target, plist_t source);
/********************************************
* *
* Getters *
* *
********************************************/
/**
* Get the parent of a node
*
* @param node the parent (NULL if node is root)
*/
plist_t plist_get_parent(plist_t node);
/**
* Get the #plist_type of a node.
*
* @param node the node
* @return the type of the node
*/
plist_type plist_get_node_type(plist_t node);
/**
* Get the value of a #PLIST_KEY node.
* This function does nothing if node is not of type #PLIST_KEY
*
* @param node the node
* @param val a pointer to a C-string. This function allocates the memory,
* caller is responsible for freeing it.
*/
void plist_get_key_val(plist_t node, char **val);
/**
* Get the value of a #PLIST_STRING node.
* This function does nothing if node is not of type #PLIST_STRING
*
* @param node the node
* @param val a pointer to a C-string. This function allocates the memory,
* caller is responsible for freeing it. Data is UTF-8 encoded.
*/
void plist_get_string_val(plist_t node, char **val);
/**
* Get the value of a #PLIST_BOOLEAN node.
* This function does nothing if node is not of type #PLIST_BOOLEAN
*
* @param node the node
* @param val a pointer to a uint8_t variable.
*/
void plist_get_bool_val(plist_t node, uint8_t * val);
/**
* Get the value of a #PLIST_UINT node.
* This function does nothing if node is not of type #PLIST_UINT
*
* @param node the node
* @param val a pointer to a uint64_t variable.
*/
void plist_get_uint_val(plist_t node, uint64_t * val);
/**
* Get the value of a #PLIST_REAL node.
* This function does nothing if node is not of type #PLIST_REAL
*
* @param node the node
* @param val a pointer to a double variable.
*/
void plist_get_real_val(plist_t node, double *val);
/**
* Get the value of a #PLIST_DATA node.
* This function does nothing if node is not of type #PLIST_DATA
*
* @param node the node
* @param val a pointer to an unallocated char buffer. This function allocates the memory,
* caller is responsible for freeing it.
* @param length the length of the buffer
*/
void plist_get_data_val(plist_t node, char **val, uint64_t * length);
/**
* Get the value of a #PLIST_DATE node.
* This function does nothing if node is not of type #PLIST_DATE
*
* @param node the node
* @param sec a pointer to an int32_t variable. Represents the number of seconds since 01/01/2001.
* @param usec a pointer to an int32_t variable. Represents the number of microseconds
*/
void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec);
/**
* Get the value of a #PLIST_UID node.
* This function does nothing if node is not of type #PLIST_UID
*
* @param node the node
* @param val a pointer to a uint64_t variable.
*/
void plist_get_uid_val(plist_t node, uint64_t * val);
/********************************************
* *
* Setters *
* *
********************************************/
/**
* Set the value of a node.
* Forces type of node to #PLIST_KEY
*
* @param node the node
* @param val the key value
*/
void plist_set_key_val(plist_t node, const char *val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_STRING
*
* @param node the node
* @param val the string value. The string is copied when set and will be
* freed by the node.
*/
void plist_set_string_val(plist_t node, const char *val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_BOOLEAN
*
* @param node the node
* @param val the boolean value
*/
void plist_set_bool_val(plist_t node, uint8_t val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_UINT
*
* @param node the node
* @param val the unsigned integer value
*/
void plist_set_uint_val(plist_t node, uint64_t val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_REAL
*
* @param node the node
* @param val the real value
*/
void plist_set_real_val(plist_t node, double val);
/**
* Set the value of a node.
* Forces type of node to #PLIST_DATA
*
* @param node the node
* @param val the binary buffer. The buffer is copied when set and will
* be freed by the node.
* @param length the length of the buffer
*/
void plist_set_data_val(plist_t node, const char *val, uint64_t length);
/**
* Set the value of a node.
* Forces type of node to #PLIST_DATE
*
* @param node the node
* @param sec the number of seconds since 01/01/2001
* @param usec the number of microseconds
*/
void plist_set_date_val(plist_t node, int32_t sec, int32_t usec);
/**
* Set the value of a node.
* Forces type of node to #PLIST_UID
*
* @param node the node
* @param val the unsigned integer value
*/
void plist_set_uid_val(plist_t node, uint64_t val);
/********************************************
* *
* Import & Export *
* *
********************************************/
/**
* Export the #plist_t structure to XML format.
*
* @param plist the root node to export
* @param plist_xml a pointer to a C-string. This function allocates the memory,
* caller is responsible for freeing it. Data is UTF-8 encoded.
* @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer.
*/
void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length);
/**
* Export the #plist_t structure to binary format.
*
* @param plist the root node to export
* @param plist_bin a pointer to a char* buffer. This function allocates the memory,
* caller is responsible for freeing it.
* @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer.
*/
void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length);
/**
* Import the #plist_t structure from XML format.
*
* @param plist_xml a pointer to the xml buffer.
* @param length length of the buffer to read.
* @param plist a pointer to the imported plist.
*/
void plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist);
/**
* Import the #plist_t structure from binary format.
*
* @param plist_bin a pointer to the xml buffer.
* @param length length of the buffer to read.
* @param plist a pointer to the imported plist.
*/
void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist);
/**
* Import the #plist_t structure from memory data.
* This method will look at the first bytes of plist_data
* to determine if plist_data contains a binary or XML plist.
*
* @param plist_data a pointer to the memory buffer containing plist data.
* @param length length of the buffer to read.
* @param plist a pointer to the imported plist.
*/
void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist);
/**
* Test if in-memory plist data is binary or XML
* This method will look at the first bytes of plist_data
* to determine if plist_data contains a binary or XML plist.
* This method is not validating the whole memory buffer to check if the
* content is truly a plist, it's only using some heuristic on the first few
* bytes of plist_data.
*
* @param plist_data a pointer to the memory buffer containing plist data.
* @param length length of the buffer to read.
* @return 1 if the buffer is a binary plist, 0 otherwise.
*/
int plist_is_binary(const char *plist_data, uint32_t length);
/********************************************
* *
* Utils *
* *
********************************************/
/**
* Get a node from its path. Each path element depends on the associated father node type.
* For Dictionaries, var args are casted to const char*, for arrays, var args are caster to uint32_t
* Search is breath first order.
*
* @param plist the node to access result from.
* @param length length of the path to access
* @return the value to access.
*/
plist_t plist_access_path(plist_t plist, uint32_t length, ...);
/**
* Variadic version of #plist_access_path.
*
* @param plist the node to access result from.
* @param length length of the path to access
* @param v list of array's index and dic'st key
* @return the value to access.
*/
plist_t plist_access_pathv(plist_t plist, uint32_t length, va_list v);
/**
* Compare two node values
*
* @param node_l left node to compare
* @param node_r rigth node to compare
* @return TRUE is type and value match, FALSE otherwise.
*/
char plist_compare_node_value(plist_t node_l, plist_t node_r);
#define _PLIST_IS_TYPE(__plist, __plist_type) (__plist && (plist_get_node_type(__plist) == PLIST_##__plist_type))
/* Helper macros for the different plist types */
#define PLIST_IS_BOOLEAN(__plist) _PLIST_IS_TYPE(__plist, BOOLEAN)
#define PLIST_IS_UINT(__plist) _PLIST_IS_TYPE(__plist, UINT)
#define PLIST_IS_REAL(__plist) _PLIST_IS_TYPE(__plist, REAL)
#define PLIST_IS_STRING(__plist) _PLIST_IS_TYPE(__plist, STRING)
#define PLIST_IS_ARRAY(__plist) _PLIST_IS_TYPE(__plist, ARRAY)
#define PLIST_IS_DICT(__plist) _PLIST_IS_TYPE(__plist, DICT)
#define PLIST_IS_DATE(__plist) _PLIST_IS_TYPE(__plist, DATE)
#define PLIST_IS_DATA(__plist) _PLIST_IS_TYPE(__plist, DATA)
#define PLIST_IS_KEY(__plist) _PLIST_IS_TYPE(__plist, KEY)
#define PLIST_IS_UID(__plist) _PLIST_IS_TYPE(__plist, UID)
/*@}*/
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,61 +0,0 @@
/*
* ptrarray.c
* simple pointer array implementation
*
* Copyright (c) 2011 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ptrarray.h"
ptrarray_t *ptr_array_new(int capacity)
{
ptrarray_t *pa = (ptrarray_t*)malloc(sizeof(ptrarray_t));
pa->pdata = (void**)malloc(sizeof(void*) * capacity);
pa->capacity = capacity;
pa->capacity_step = (capacity > 4096) ? 4096 : capacity;
pa->len = 0;
return pa;
}
void ptr_array_free(ptrarray_t *pa)
{
if (!pa) return;
if (pa->pdata) {
free(pa->pdata);
}
free(pa);
}
void ptr_array_add(ptrarray_t *pa, void *data)
{
if (!pa || !pa->pdata || !data) return;
size_t remaining = pa->capacity-pa->len;
if (remaining == 0) {
pa->pdata = realloc(pa->pdata, sizeof(void*) * (pa->capacity + pa->capacity_step));
pa->capacity += pa->capacity_step;
}
pa->pdata[pa->len] = data;
pa->len++;
}
void* ptr_array_index(ptrarray_t *pa, size_t array_index)
{
if (!pa) return NULL;
if (array_index >= pa->len) {
return NULL;
}
return pa->pdata[array_index];
}

View File

@@ -1,36 +0,0 @@
/*
* ptrarray.h
* header file for simple pointer array implementation
*
* Copyright (c) 2011 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PTRARRAY_H
#define PTRARRAY_H
#include <stdlib.h>
typedef struct ptrarray_t {
void **pdata;
size_t len;
size_t capacity;
size_t capacity_step;
} ptrarray_t;
ptrarray_t *ptr_array_new(int capacity);
void ptr_array_free(ptrarray_t *pa);
void ptr_array_add(ptrarray_t *pa, void *data);
void* ptr_array_index(ptrarray_t *pa, size_t index);
#endif

View File

@@ -1,34 +0,0 @@
/*
* strbuf.h
* header file for simple string buffer, using the bytearray as underlying
* structure.
*
* Copyright (c) 2016 Nikias Bassen, All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef STRBUF_H
#define STRBUF_H
#include <stdlib.h>
#include "bytearray.h"
typedef struct bytearray_t strbuf_t;
#define str_buf_new(__sz) byte_array_new(__sz)
#define str_buf_free(__ba) byte_array_free(__ba)
#define str_buf_grow(__ba, __am) byte_array_grow(__ba, __am)
#define str_buf_append(__ba, __str, __len) byte_array_append(__ba, (void*)(__str), __len)
#endif

View File

@@ -1,812 +0,0 @@
/*
Copyright (c) 2007-2010 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
The MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/*
Programmers who have available to them 64-bit time values as a 'long
long' type can use localtime64_r() and gmtime64_r() which correctly
converts the time even on 32-bit systems. Whether you have 64-bit time
values will depend on the operating system.
localtime64_r() is a 64-bit equivalent of localtime_r().
gmtime64_r() is a 64-bit equivalent of gmtime_r().
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "time64.h"
#include "time64_limits.h"
static const char days_in_month[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
static const short julian_days_by_month[2][12] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};
static char wday_name[7][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static char mon_name[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const short length_of_year[2] = { 365, 366 };
/* Some numbers relating to the gregorian cycle */
static const Year years_in_gregorian_cycle = 400;
#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
static const Time64_T seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
/* Year range we can trust the time funcitons with */
#define MAX_SAFE_YEAR 2037
#define MIN_SAFE_YEAR 1971
/* 28 year Julian calendar cycle */
#define SOLAR_CYCLE_LENGTH 28
/* Year cycle from MAX_SAFE_YEAR down. */
static const short safe_years_high[SOLAR_CYCLE_LENGTH] = {
2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023,
2024, 2025, 2026, 2027,
2028, 2029, 2030, 2031,
2032, 2033, 2034, 2035,
2036, 2037, 2010, 2011,
2012, 2013, 2014, 2015
};
/* Year cycle from MIN_SAFE_YEAR up */
static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
1996, 1997, 1998, 1971,
1972, 1973, 1974, 1975,
1976, 1977, 1978, 1979,
1980, 1981, 1982, 1983,
1984, 1985, 1986, 1987,
1988, 1989, 1990, 1991,
1992, 1993, 1994, 1995,
};
/* This isn't used, but it's handy to look at */
#if 0
static const char dow_year_start[SOLAR_CYCLE_LENGTH] = {
5, 0, 1, 2, /* 0 2016 - 2019 */
3, 5, 6, 0, /* 4 */
1, 3, 4, 5, /* 8 1996 - 1998, 1971*/
6, 1, 2, 3, /* 12 1972 - 1975 */
4, 6, 0, 1, /* 16 */
2, 4, 5, 6, /* 20 2036, 2037, 2010, 2011 */
0, 2, 3, 4 /* 24 2012, 2013, 2014, 2015 */
};
#endif
/* Let's assume people are going to be looking for dates in the future.
Let's provide some cheats so you can skip ahead.
This has a 4x speed boost when near 2008.
*/
/* Number of days since epoch on Jan 1st, 2008 GMT */
#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
#define CHEAT_YEARS 108
#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
#ifdef USE_SYSTEM_LOCALTIME
# define SHOULD_USE_SYSTEM_LOCALTIME(a) ( \
(a) <= SYSTEM_LOCALTIME_MAX && \
(a) >= SYSTEM_LOCALTIME_MIN \
)
#else
# define SHOULD_USE_SYSTEM_LOCALTIME(a) (0)
#endif
#ifdef USE_SYSTEM_GMTIME
# define SHOULD_USE_SYSTEM_GMTIME(a) ( \
(a) <= SYSTEM_GMTIME_MAX && \
(a) >= SYSTEM_GMTIME_MIN \
)
#else
# define SHOULD_USE_SYSTEM_GMTIME(a) (0)
#endif
/* Multi varadic macros are a C99 thing, alas */
#ifdef TIME_64_DEBUG
# define TIME64_TRACE(format) (fprintf(stderr, format))
# define TIME64_TRACE1(format, var1) (fprintf(stderr, format, var1))
# define TIME64_TRACE2(format, var1, var2) (fprintf(stderr, format, var1, var2))
# define TIME64_TRACE3(format, var1, var2, var3) (fprintf(stderr, format, var1, var2, var3))
#else
# define TIME64_TRACE(format) ((void)0)
# define TIME64_TRACE1(format, var1) ((void)0)
# define TIME64_TRACE2(format, var1, var2) ((void)0)
# define TIME64_TRACE3(format, var1, var2, var3) ((void)0)
#endif
static int is_exception_century(Year year)
{
int is_exception = ((year % 100 == 0) && !(year % 400 == 0));
TIME64_TRACE1("# is_exception_century: %s\n", is_exception ? "yes" : "no");
return(is_exception);
}
/* Compare two dates.
The result is like cmp.
Ignores things like gmtoffset and dst
*/
static int cmp_date( const struct TM* left, const struct tm* right ) {
if( left->tm_year > right->tm_year )
return 1;
else if( left->tm_year < right->tm_year )
return -1;
if( left->tm_mon > right->tm_mon )
return 1;
else if( left->tm_mon < right->tm_mon )
return -1;
if( left->tm_mday > right->tm_mday )
return 1;
else if( left->tm_mday < right->tm_mday )
return -1;
if( left->tm_hour > right->tm_hour )
return 1;
else if( left->tm_hour < right->tm_hour )
return -1;
if( left->tm_min > right->tm_min )
return 1;
else if( left->tm_min < right->tm_min )
return -1;
if( left->tm_sec > right->tm_sec )
return 1;
else if( left->tm_sec < right->tm_sec )
return -1;
return 0;
}
/* Check if a date is safely inside a range.
The intention is to check if its a few days inside.
*/
static int date_in_safe_range( const struct TM* date, const struct tm* min, const struct tm* max ) {
if( cmp_date(date, min) == -1 )
return 0;
if( cmp_date(date, max) == 1 )
return 0;
return 1;
}
/* timegm() is not in the C or POSIX spec, but it is such a useful
extension I would be remiss in leaving it out. Also I need it
for localtime64()
*/
Time64_T timegm64(const struct TM *date) {
Time64_T days = 0;
Time64_T seconds = 0;
Year year;
Year orig_year = (Year)date->tm_year;
int cycles = 0;
if( orig_year > 100 ) {
cycles = (orig_year - 100) / 400;
orig_year -= cycles * 400;
days += (Time64_T)cycles * days_in_gregorian_cycle;
}
else if( orig_year < -300 ) {
cycles = (orig_year - 100) / 400;
orig_year -= cycles * 400;
days += (Time64_T)cycles * days_in_gregorian_cycle;
}
TIME64_TRACE3("# timegm/ cycles: %d, days: %lld, orig_year: %lld\n", cycles, days, orig_year);
if( orig_year > 70 ) {
year = 70;
while( year < orig_year ) {
days += length_of_year[IS_LEAP(year)];
year++;
}
}
else if ( orig_year < 70 ) {
year = 69;
do {
days -= length_of_year[IS_LEAP(year)];
year--;
} while( year >= orig_year );
}
days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
days += date->tm_mday - 1;
seconds = days * 60 * 60 * 24;
seconds += date->tm_hour * 60 * 60;
seconds += date->tm_min * 60;
seconds += date->tm_sec;
return(seconds);
}
static int check_tm(struct TM *tm)
{
/* Don't forget leap seconds */
assert(tm->tm_sec >= 0);
assert(tm->tm_sec <= 61);
assert(tm->tm_min >= 0);
assert(tm->tm_min <= 59);
assert(tm->tm_hour >= 0);
assert(tm->tm_hour <= 23);
assert(tm->tm_mday >= 1);
assert(tm->tm_mday <= days_in_month[IS_LEAP(tm->tm_year)][tm->tm_mon]);
assert(tm->tm_mon >= 0);
assert(tm->tm_mon <= 11);
assert(tm->tm_wday >= 0);
assert(tm->tm_wday <= 6);
assert(tm->tm_yday >= 0);
assert(tm->tm_yday <= length_of_year[IS_LEAP(tm->tm_year)]);
#ifdef HAVE_TM_TM_GMTOFF
assert(tm->tm_gmtoff >= -24 * 60 * 60);
assert(tm->tm_gmtoff <= 24 * 60 * 60);
#endif
return 1;
}
/* The exceptional centuries without leap years cause the cycle to
shift by 16
*/
static Year cycle_offset(Year year)
{
const Year start_year = 2000;
Year year_diff = year - start_year;
Year exceptions;
if( year > start_year )
year_diff--;
exceptions = year_diff / 100;
exceptions -= year_diff / 400;
TIME64_TRACE3("# year: %lld, exceptions: %lld, year_diff: %lld\n",
year, exceptions, year_diff);
return exceptions * 16;
}
/* For a given year after 2038, pick the latest possible matching
year in the 28 year calendar cycle.
A matching year...
1) Starts on the same day of the week.
2) Has the same leap year status.
This is so the calendars match up.
Also the previous year must match. When doing Jan 1st you might
wind up on Dec 31st the previous year when doing a -UTC time zone.
Finally, the next year must have the same start day of week. This
is for Dec 31st with a +UTC time zone.
It doesn't need the same leap year status since we only care about
January 1st.
*/
static int safe_year(const Year year)
{
int safe_year= (int)year;
Year year_cycle;
if( year >= MIN_SAFE_YEAR && year <= MAX_SAFE_YEAR ) {
return safe_year;
}
year_cycle = year + cycle_offset(year);
/* safe_years_low is off from safe_years_high by 8 years */
if( year < MIN_SAFE_YEAR )
year_cycle -= 8;
/* Change non-leap xx00 years to an equivalent */
if( is_exception_century(year) )
year_cycle += 11;
/* Also xx01 years, since the previous year will be wrong */
if( is_exception_century(year - 1) )
year_cycle += 17;
year_cycle %= SOLAR_CYCLE_LENGTH;
if( year_cycle < 0 )
year_cycle = SOLAR_CYCLE_LENGTH + year_cycle;
assert( year_cycle >= 0 );
assert( year_cycle < SOLAR_CYCLE_LENGTH );
if( year < MIN_SAFE_YEAR )
safe_year = safe_years_low[year_cycle];
else if( year > MAX_SAFE_YEAR )
safe_year = safe_years_high[year_cycle];
else
assert(0);
TIME64_TRACE3("# year: %lld, year_cycle: %lld, safe_year: %d\n",
year, year_cycle, safe_year);
assert(safe_year <= MAX_SAFE_YEAR && safe_year >= MIN_SAFE_YEAR);
return safe_year;
}
void copy_tm_to_TM64(const struct tm *src, struct TM *dest) {
if( src == NULL ) {
memset(dest, 0, sizeof(*dest));
}
else {
# ifdef USE_TM64
dest->tm_sec = src->tm_sec;
dest->tm_min = src->tm_min;
dest->tm_hour = src->tm_hour;
dest->tm_mday = src->tm_mday;
dest->tm_mon = src->tm_mon;
dest->tm_year = (Year)src->tm_year;
dest->tm_wday = src->tm_wday;
dest->tm_yday = src->tm_yday;
dest->tm_isdst = src->tm_isdst;
# ifdef HAVE_TM_TM_GMTOFF
dest->tm_gmtoff = src->tm_gmtoff;
# endif
# ifdef HAVE_TM_TM_ZONE
dest->tm_zone = src->tm_zone;
# endif
# else
/* They're the same type */
memcpy(dest, src, sizeof(*dest));
# endif
}
}
void copy_TM64_to_tm(const struct TM *src, struct tm *dest) {
if( src == NULL ) {
memset(dest, 0, sizeof(*dest));
}
else {
# ifdef USE_TM64
dest->tm_sec = src->tm_sec;
dest->tm_min = src->tm_min;
dest->tm_hour = src->tm_hour;
dest->tm_mday = src->tm_mday;
dest->tm_mon = src->tm_mon;
dest->tm_year = (int)src->tm_year;
dest->tm_wday = src->tm_wday;
dest->tm_yday = src->tm_yday;
dest->tm_isdst = src->tm_isdst;
# ifdef HAVE_TM_TM_GMTOFF
dest->tm_gmtoff = src->tm_gmtoff;
# endif
# ifdef HAVE_TM_TM_ZONE
dest->tm_zone = src->tm_zone;
# endif
# else
/* They're the same type */
memcpy(dest, src, sizeof(*dest));
# endif
}
}
#ifndef HAVE_LOCALTIME_R
/* Simulate localtime_r() to the best of our ability */
static struct tm * fake_localtime_r(const time_t *time, struct tm *result) {
const struct tm *static_result = localtime(time);
assert(result != NULL);
if( static_result == NULL ) {
memset(result, 0, sizeof(*result));
return NULL;
}
else {
memcpy(result, static_result, sizeof(*result));
return result;
}
}
#endif
#ifndef HAVE_GMTIME_R
/* Simulate gmtime_r() to the best of our ability */
static struct tm * fake_gmtime_r(const time_t *time, struct tm *result) {
const struct tm *static_result = gmtime(time);
assert(result != NULL);
if( static_result == NULL ) {
memset(result, 0, sizeof(*result));
return NULL;
}
else {
memcpy(result, static_result, sizeof(*result));
return result;
}
}
#endif
static Time64_T seconds_between_years(Year left_year, Year right_year) {
int increment = (left_year > right_year) ? 1 : -1;
Time64_T seconds = 0;
int cycles;
if( left_year > 2400 ) {
cycles = (left_year - 2400) / 400;
left_year -= cycles * 400;
seconds += cycles * seconds_in_gregorian_cycle;
}
else if( left_year < 1600 ) {
cycles = (left_year - 1600) / 400;
left_year += cycles * 400;
seconds += cycles * seconds_in_gregorian_cycle;
}
while( left_year != right_year ) {
seconds += length_of_year[IS_LEAP(right_year - 1900)] * 60 * 60 * 24;
right_year += increment;
}
return seconds * increment;
}
Time64_T mktime64(struct TM *input_date) {
struct tm safe_date;
struct TM date;
Time64_T time;
Year year = input_date->tm_year + 1900;
if( date_in_safe_range(input_date, &SYSTEM_MKTIME_MIN, &SYSTEM_MKTIME_MAX) )
{
copy_TM64_to_tm(input_date, &safe_date);
time = (Time64_T)mktime(&safe_date);
/* Correct the possibly out of bound input date */
copy_tm_to_TM64(&safe_date, input_date);
return time;
}
/* Have to make the year safe in date else it won't fit in safe_date */
date = *input_date;
date.tm_year = safe_year(year) - 1900;
copy_TM64_to_tm(&date, &safe_date);
time = (Time64_T)mktime(&safe_date);
/* Correct the user's possibly out of bound input date */
copy_tm_to_TM64(&safe_date, input_date);
time += seconds_between_years(year, (Year)(safe_date.tm_year + 1900));
return time;
}
/* Because I think mktime() is a crappy name */
Time64_T timelocal64(struct TM *date) {
return mktime64(date);
}
struct TM *gmtime64_r (const Time64_T *in_time, struct TM *p)
{
int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
Time64_T v_tm_tday;
int leap;
Time64_T m;
Time64_T time = *in_time;
Year year = 70;
int cycles = 0;
assert(p != NULL);
/* Use the system gmtime() if time_t is small enough */
if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
time_t safe_time = (time_t)*in_time;
struct tm safe_date;
GMTIME_R(&safe_time, &safe_date);
copy_tm_to_TM64(&safe_date, p);
assert(check_tm(p));
return p;
}
#ifdef HAVE_TM_TM_GMTOFF
p->tm_gmtoff = 0;
#endif
p->tm_isdst = 0;
#ifdef HAVE_TM_TM_ZONE
p->tm_zone = (char*)"UTC";
#endif
v_tm_sec = (int)(time % 60);
time /= 60;
v_tm_min = (int)(time % 60);
time /= 60;
v_tm_hour = (int)(time % 24);
time /= 24;
v_tm_tday = time;
WRAP (v_tm_sec, v_tm_min, 60);
WRAP (v_tm_min, v_tm_hour, 60);
WRAP (v_tm_hour, v_tm_tday, 24);
v_tm_wday = (int)((v_tm_tday + 4) % 7);
if (v_tm_wday < 0)
v_tm_wday += 7;
m = v_tm_tday;
if (m >= CHEAT_DAYS) {
year = CHEAT_YEARS;
m -= CHEAT_DAYS;
}
if (m >= 0) {
/* Gregorian cycles, this is huge optimization for distant times */
cycles = (int)(m / (Time64_T) days_in_gregorian_cycle);
if( cycles ) {
m -= (cycles * (Time64_T) days_in_gregorian_cycle);
year += (cycles * years_in_gregorian_cycle);
}
/* Years */
leap = IS_LEAP (year);
while (m >= (Time64_T) length_of_year[leap]) {
m -= (Time64_T) length_of_year[leap];
year++;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 0;
while (m >= (Time64_T) days_in_month[leap][v_tm_mon]) {
m -= (Time64_T) days_in_month[leap][v_tm_mon];
v_tm_mon++;
}
} else {
year--;
/* Gregorian cycles */
cycles = (int)((m / (Time64_T) days_in_gregorian_cycle) + 1);
if( cycles ) {
m -= (cycles * (Time64_T) days_in_gregorian_cycle);
year += (cycles * years_in_gregorian_cycle);
}
/* Years */
leap = IS_LEAP (year);
while (m < (Time64_T) -length_of_year[leap]) {
m += (Time64_T) length_of_year[leap];
year--;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 11;
while (m < (Time64_T) -days_in_month[leap][v_tm_mon]) {
m += (Time64_T) days_in_month[leap][v_tm_mon];
v_tm_mon--;
}
m += (Time64_T) days_in_month[leap][v_tm_mon];
}
p->tm_year = year;
if( p->tm_year != year ) {
#ifdef EOVERFLOW
errno = EOVERFLOW;
#endif
return NULL;
}
/* At this point m is less than a year so casting to an int is safe */
p->tm_mday = (int) m + 1;
p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
p->tm_sec = v_tm_sec;
p->tm_min = v_tm_min;
p->tm_hour = v_tm_hour;
p->tm_mon = v_tm_mon;
p->tm_wday = v_tm_wday;
assert(check_tm(p));
return p;
}
struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm)
{
time_t safe_time;
struct tm safe_date;
struct TM gm_tm;
Year orig_year;
int month_diff;
assert(local_tm != NULL);
/* Use the system localtime() if time_t is small enough */
if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) {
safe_time = (time_t)*time;
TIME64_TRACE1("Using system localtime for %lld\n", *time);
LOCALTIME_R(&safe_time, &safe_date);
copy_tm_to_TM64(&safe_date, local_tm);
assert(check_tm(local_tm));
return local_tm;
}
if( gmtime64_r(time, &gm_tm) == NULL ) {
TIME64_TRACE1("gmtime64_r returned null for %lld\n", *time);
return NULL;
}
orig_year = gm_tm.tm_year;
if (gm_tm.tm_year > (2037 - 1900) ||
gm_tm.tm_year < (1970 - 1900)
)
{
TIME64_TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year);
gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900;
}
safe_time = (time_t)timegm64(&gm_tm);
if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) {
TIME64_TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time);
return NULL;
}
copy_tm_to_TM64(&safe_date, local_tm);
local_tm->tm_year = orig_year;
if( local_tm->tm_year != orig_year ) {
TIME64_TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n",
(Year)local_tm->tm_year, (Year)orig_year);
#ifdef EOVERFLOW
errno = EOVERFLOW;
#endif
return NULL;
}
month_diff = local_tm->tm_mon - gm_tm.tm_mon;
/* When localtime is Dec 31st previous year and
gmtime is Jan 1st next year.
*/
if( month_diff == 11 ) {
local_tm->tm_year--;
}
/* When localtime is Jan 1st, next year and
gmtime is Dec 31st, previous year.
*/
if( month_diff == -11 ) {
local_tm->tm_year++;
}
/* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st
in a non-leap xx00. There is one point in the cycle
we can't account for which the safe xx00 year is a leap
year. So we need to correct for Dec 31st comming out as
the 366th day of the year.
*/
if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 )
local_tm->tm_yday--;
assert(check_tm(local_tm));
return local_tm;
}
static int valid_tm_wday( const struct TM* date ) {
if( 0 <= date->tm_wday && date->tm_wday <= 6 )
return 1;
else
return 0;
}
static int valid_tm_mon( const struct TM* date ) {
if( 0 <= date->tm_mon && date->tm_mon <= 11 )
return 1;
else
return 0;
}
char *asctime64_r( const struct TM* date, char *result ) {
/* I figure everything else can be displayed, even hour 25, but if
these are out of range we walk off the name arrays */
if( !valid_tm_wday(date) || !valid_tm_mon(date) )
return NULL;
sprintf(result, TM64_ASCTIME_FORMAT,
wday_name[date->tm_wday],
mon_name[date->tm_mon],
date->tm_mday, date->tm_hour,
date->tm_min, date->tm_sec,
1900 + date->tm_year);
return result;
}
char *ctime64_r( const Time64_T* time, char* result ) {
struct TM date;
localtime64_r( time, &date );
return asctime64_r( &date, result );
}

View File

@@ -1,81 +0,0 @@
#ifndef TIME64_H
# define TIME64_H
#include <time.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Set our custom types */
typedef long long Int64;
typedef Int64 Time64_T;
typedef Int64 Year;
/* A copy of the tm struct but with a 64 bit year */
struct TM64 {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
Year tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
#ifdef HAVE_TM_TM_GMTOFF
long tm_gmtoff;
#endif
#ifdef HAVE_TM_TM_ZONE
char *tm_zone;
#endif
};
/* Decide which tm struct to use */
#ifdef USE_TM64
#define TM TM64
#else
#define TM tm
#endif
/* Declare public functions */
struct TM *gmtime64_r (const Time64_T *, struct TM *);
struct TM *localtime64_r (const Time64_T *, struct TM *);
char *asctime64_r (const struct TM *, char *);
char *ctime64_r (const Time64_T*, char*);
Time64_T timegm64 (const struct TM *);
Time64_T mktime64 (struct TM *);
Time64_T timelocal64 (struct TM *);
/* Not everyone has gm/localtime_r(), provide a replacement */
#ifdef HAVE_LOCALTIME_R
# define LOCALTIME_R(clock, result) localtime_r(clock, result)
#else
# define LOCALTIME_R(clock, result) fake_localtime_r(clock, result)
#endif
#ifdef HAVE_GMTIME_R
# define GMTIME_R(clock, result) gmtime_r(clock, result)
#else
# define GMTIME_R(clock, result) fake_gmtime_r(clock, result)
#endif
/* Use a different asctime format depending on how big the year is */
#ifdef USE_TM64
#define TM64_ASCTIME_FORMAT "%.3s %.3s%3d %.2d:%.2d:%.2d %lld\n"
#else
#define TM64_ASCTIME_FORMAT "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n"
#endif
void copy_tm_to_TM64(const struct tm *src, struct TM *dest);
void copy_TM64_to_tm(const struct TM *src, struct tm *dest);
#endif

View File

@@ -1,97 +0,0 @@
/*
Maximum and minimum inputs your system's respective time functions
can correctly handle. time64.h will use your system functions if
the input falls inside these ranges and corresponding USE_SYSTEM_*
constant is defined.
*/
#ifndef TIME64_LIMITS_H
#define TIME64_LIMITS_H
#include <time.h>
/* Max/min for localtime() */
#define SYSTEM_LOCALTIME_MAX 2147483647
#define SYSTEM_LOCALTIME_MIN -2147483647-1
/* Max/min for gmtime() */
#define SYSTEM_GMTIME_MAX 2147483647
#define SYSTEM_GMTIME_MIN -2147483647-1
/* Max/min for mktime() */
static const struct tm SYSTEM_MKTIME_MAX = {
7,
14,
19,
18,
0,
138,
1,
17,
0
#ifdef HAVE_TM_TM_GMTOFF
,-28800
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"PST"
#endif
};
static const struct tm SYSTEM_MKTIME_MIN = {
52,
45,
12,
13,
11,
1,
5,
346,
0
#ifdef HAVE_TM_TM_GMTOFF
,-28800
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"PST"
#endif
};
/* Max/min for timegm() */
#ifdef HAVE_TIMEGM
static const struct tm SYSTEM_TIMEGM_MAX = {
7,
14,
3,
19,
0,
138,
2,
18,
0
#ifdef HAVE_TM_TM_GMTOFF
,0
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"UTC"
#endif
};
static const struct tm SYSTEM_TIMEGM_MIN = {
52,
45,
20,
13,
11,
1,
5,
346,
0
#ifdef HAVE_TM_TM_GMTOFF
,0
#endif
#ifdef HAVE_TM_TM_ZONE
,(char*)"UTC"
#endif
};
#endif /* HAVE_TIMEGM */
#endif /* TIME64_LIMITS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -15,11 +15,11 @@
/* This file should be only included from raop.c as it defines static handler
* functions and depends on raop internals */
#include "plist/plist/plist.h"
#include "dnssdint.h"
#include "utils.h"
#include <ctype.h>
#include <stdlib.h>
#include <plist/plist.h>
typedef void (*raop_handler_t)(raop_conn_t *, http_request_t *,
http_response_t *, char **, int *);
@@ -169,7 +169,7 @@ raop_handler_pairsetup(raop_conn_t *conn,
http_request_t *request, http_response_t *response,
char **response_data, int *response_datalen)
{
unsigned char public_key[32];
unsigned char public_key[ED25519_KEY_SIZE];
const char *data;
int datalen;
@@ -198,8 +198,8 @@ raop_handler_pairverify(raop_conn_t *conn,
if (pairing_session_check_handshake_status(conn->pairing)) {
return;
}
unsigned char public_key[32];
unsigned char signature[64];
unsigned char public_key[X25519_KEY_SIZE];
unsigned char signature[PAIRING_SIG_SIZE];
const unsigned char *data;
int datalen;
@@ -210,12 +210,12 @@ raop_handler_pairverify(raop_conn_t *conn,
}
switch (data[0]) {
case 1:
if (datalen != 4 + 32 + 32) {
if (datalen != 4 + X25519_KEY_SIZE + X25519_KEY_SIZE) {
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
return;
}
/* We can fall through these errors, the result will just be garbage... */
if (pairing_session_handshake(conn->pairing, data + 4, data + 4 + 32)) {
if (pairing_session_handshake(conn->pairing, data + 4, data + 4 + X25519_KEY_SIZE)) {
logger_log(conn->raop->logger, LOGGER_ERR, "Error initializing pair-verify handshake");
}
if (pairing_session_get_public_key(conn->pairing, public_key)) {
@@ -233,7 +233,7 @@ raop_handler_pairverify(raop_conn_t *conn,
}
break;
case 0:
if (datalen != 4 + 64) {
if (datalen != 4 + PAIRING_SIG_SIZE) {
logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data");
return;
}
@@ -363,7 +363,7 @@ raop_handler_setup(raop_conn_t *conn,
// ekey is 72 bytes, aeskey is 16 bytes
int ret = fairplay_decrypt(conn->fairplay, (unsigned char*) ekey, aeskey);
logger_log(conn->raop->logger, LOGGER_DEBUG, "fairplay_decrypt ret = %d", ret);
unsigned char ecdh_secret[32];
unsigned char ecdh_secret[X25519_KEY_SIZE];
pairing_get_ecdh_secret_key(conn->pairing, ecdh_secret);
// Time port
@@ -478,12 +478,11 @@ raop_handler_get_parameter(raop_conn_t *conn,
if (!strcmp(content_type, "text/parameters")) {
const char *current = data;
while (current) {
while (current && (datalen - (current - data) > 0)) {
const char *next;
int handled = 0;
/* This is a bit ugly, but seems to be how airport works too */
if (!strncmp(current, "volume\r\n", 8)) {
if ((datalen - (current - data) >= 8) && !strncmp(current, "volume\r\n", 8)) {
const char volume[] = "volume: 0.0\r\n";
http_response_add_header(response, "Content-Type", "text/parameters");
@@ -491,15 +490,18 @@ raop_handler_get_parameter(raop_conn_t *conn,
if (*response_data) {
*response_datalen = strlen(*response_data);
}
handled = 1;
return;
}
next = strstr(current, "\r\n");
if (next && !handled) {
logger_log(conn->raop->logger, LOGGER_WARNING,
"Found an unknown parameter: %.*s", (next - current), current);
current = next + 2;
} else if (next) {
for (next = current ; (datalen - (next - data) > 0) ; ++next)
if (*next == '\r')
break;
if ((datalen - (next - data) >= 2) && !strncmp(next, "\r\n", 2)) {
if ((next - current) > 0) {
logger_log(conn->raop->logger, LOGGER_WARNING,
"Found an unknown parameter: %.*s", (next - current), current);
}
current = next + 2;
} else {
current = NULL;
@@ -524,11 +526,11 @@ raop_handler_set_parameter(raop_conn_t *conn,
datastr = calloc(1, datalen+1);
if (data && datastr && conn->raop_rtp) {
memcpy(datastr, data, datalen);
if (!strncmp(datastr, "volume: ", 8)) {
if ((datalen >= 8) && !strncmp(datastr, "volume: ", 8)) {
float vol = 0.0;
sscanf(datastr+8, "%f", &vol);
raop_rtp_set_volume(conn->raop_rtp, vol);
} else if (!strncmp(datastr, "progress: ", 10)) {
} else if ((datalen >= 10) && !strncmp(datastr, "progress: ", 10)) {
unsigned int start, curr, end;
sscanf(datastr+10, "%u/%u/%u", &start, &curr, &end);
raop_rtp_set_progress(conn->raop_rtp, start, curr, end);

View File

@@ -202,7 +202,7 @@ raop_ntp_init_socket(raop_ntp_t *raop_ntp, int use_ipv6)
// We're calling recvfrom without knowing whether there is any data, so we need a timeout
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 3000;
tv.tv_usec = 300000;
if (setsockopt(tsock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
goto sockets_cleanup;
}
@@ -219,6 +219,23 @@ raop_ntp_init_socket(raop_ntp_t *raop_ntp, int use_ipv6)
return -1;
}
static void
raop_ntp_flush_socket(int fd)
{
int bytes_available = 0;
while (ioctl(fd, FIONREAD, &bytes_available) == 0 && bytes_available > 0)
{
// We are guaranteed that we won't block, because bytes are available.
// Read 1 byte. Extra bytes in the datagram will be discarded.
char c;
int result = recvfrom(fd, &c, sizeof(c), 0, NULL, NULL);
if (result < 0)
{
break;
}
}
}
static THREAD_RETVAL
raop_ntp_thread(void *arg)
{
@@ -240,6 +257,9 @@ raop_ntp_thread(void *arg)
}
MUTEX_UNLOCK(raop_ntp->run_mutex);
// Flush the socket in case a super delayed response arrived or something
raop_ntp_flush_socket(raop_ntp->tsock);
// Send request
uint64_t send_time = raop_ntp_get_local_time(raop_ntp);
byteutils_put_ntp_timestamp(request, 24, send_time);
@@ -248,60 +268,59 @@ raop_ntp_thread(void *arg)
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp send_len = %d", send_len);
if (send_len < 0) {
logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp error sending request");
break;
} else {
// Read response
response_len = recvfrom(raop_ntp->tsock, (char *)response, sizeof(response), 0,
(struct sockaddr *) &raop_ntp->remote_saddr, &raop_ntp->remote_saddr_len);
if (response_len < 0) {
logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp receive timeout");
} else {
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp receive time type_t packetlen = %d", response_len);
int64_t t3 = (int64_t) raop_ntp_get_local_time(raop_ntp);
// Local time of the client when the NTP request packet leaves the client
int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8);
// Local time of the server when the NTP request packet arrives at the server
int64_t t1 = (int64_t) byteutils_get_ntp_timestamp(response, 16);
// Local time of the server when the response message leaves the server
int64_t t2 = (int64_t) byteutils_get_ntp_timestamp(response, 24);
// The iOS device sends its time in micro seconds relative to an arbitrary Epoch (the last boot).
// For a little bonus confusion, they add SECONDS_FROM_1900_TO_1970 * 1000000 us.
// This means we have to expect some rather huge offset, but its growth or shrink over time should be small.
raop_ntp->data_index = (raop_ntp->data_index + 1) % RAOP_NTP_DATA_COUNT;
raop_ntp->data[raop_ntp->data_index].time = t3;
raop_ntp->data[raop_ntp->data_index].offset = ((t1 - t0) + (t2 - t3)) / 2;
raop_ntp->data[raop_ntp->data_index].delay = ((t3 - t0) - (t2 - t1));
raop_ntp->data[raop_ntp->data_index].dispersion = RAOP_NTP_R_RHO + RAOP_NTP_S_RHO + (t3 - t0) * RAOP_NTP_PHI_PPM / 1000000u;
// Sort by delay
memcpy(data_sorted, raop_ntp->data, sizeof(data_sorted));
qsort(data_sorted, RAOP_NTP_DATA_COUNT, sizeof(data_sorted[0]), raop_ntp_compare);
uint64_t dispersion = 0ull;
int64_t offset = data_sorted[0].offset;
int64_t delay = data_sorted[RAOP_NTP_DATA_COUNT - 1].delay;
// Calculate dispersion
for(int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) {
unsigned long long disp = raop_ntp->data[i].dispersion + (t3 - raop_ntp->data[i].time) * RAOP_NTP_PHI_PPM / 1000000u;
dispersion += disp / two_pow_n[i];
}
MUTEX_LOCK(raop_ntp->sync_params_mutex);
int64_t correction = offset - raop_ntp->sync_offset;
raop_ntp->sync_offset = offset;
raop_ntp->sync_dispersion = dispersion;
raop_ntp->sync_delay = delay;
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp sync correction = %lld", correction);
}
}
// Read response
response_len = recvfrom(raop_ntp->tsock, (char *)response, sizeof(response), 0,
(struct sockaddr *) &raop_ntp->remote_saddr, &raop_ntp->remote_saddr_len);
if (response_len < 0) {
logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp receive timeout");
break;
}
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp receive time type_t packetlen = %d", response_len);
int64_t t3 = (int64_t) raop_ntp_get_local_time(raop_ntp);
// Local time of the client when the NTP request packet leaves the client
int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8);
// Local time of the server when the NTP request packet arrives at the server
int64_t t1 = (int64_t) byteutils_get_ntp_timestamp(response, 16);
// Local time of the server when the response message leaves the server
int64_t t2 = (int64_t) byteutils_get_ntp_timestamp(response, 24);
// The iOS device sends its time in micro seconds relative to an arbitrary Epoch (the last boot).
// For a little bonus confusion, they add SECONDS_FROM_1900_TO_1970 * 1000000 us.
// This means we have to expect some rather huge offset, but its growth or shrink over time should be small.
raop_ntp->data_index = (raop_ntp->data_index + 1) % RAOP_NTP_DATA_COUNT;
raop_ntp->data[raop_ntp->data_index].time = t3;
raop_ntp->data[raop_ntp->data_index].offset = ((t1 - t0) + (t2 - t3)) / 2;
raop_ntp->data[raop_ntp->data_index].delay = ((t3 - t0) - (t2 - t1));
raop_ntp->data[raop_ntp->data_index].dispersion = RAOP_NTP_R_RHO + RAOP_NTP_S_RHO + (t3 - t0) * RAOP_NTP_PHI_PPM / 1000000u;
// Sort by delay
memcpy(data_sorted, raop_ntp->data, sizeof(data_sorted));
qsort(data_sorted, RAOP_NTP_DATA_COUNT, sizeof(data_sorted[0]), raop_ntp_compare);
uint64_t dispersion = 0ull;
int64_t offset = data_sorted[0].offset;
int64_t delay = data_sorted[RAOP_NTP_DATA_COUNT - 1].delay;
// Calculate dispersion
for(int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) {
unsigned long long disp = raop_ntp->data[i].dispersion + (t3 - raop_ntp->data[i].time) * RAOP_NTP_PHI_PPM / 1000000u;
dispersion += disp / two_pow_n[i];
}
MUTEX_LOCK(raop_ntp->sync_params_mutex);
int64_t correction = offset - raop_ntp->sync_offset;
raop_ntp->sync_offset = offset;
raop_ntp->sync_dispersion = dispersion;
raop_ntp->sync_delay = delay;
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp sync correction = %lld", correction);
// Sleep for 3 seconds
struct timeval now;
struct timespec wait_time;
@@ -443,4 +462,4 @@ uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time)
uint64_t offset = raop_ntp->sync_offset;
MUTEX_UNLOCK(raop_ntp->sync_params_mutex);
return (uint64_t) ((int64_t) local_time) + ((int64_t) offset);
}
}

View File

@@ -20,6 +20,7 @@
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <netinet/tcp.h>
#include "raop.h"
#include "netutils.h"
@@ -218,7 +219,23 @@ raop_rtp_mirror_thread(void *arg)
logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror could not set stream socket timeout %d %s", errno, strerror(errno));
break;
}
int option;
option = 1;
if (setsockopt(stream_fd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)) < 0) {
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive %d %s", errno, strerror(errno));
}
option = 60;
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPIDLE, &option, sizeof(option)) < 0) {
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive time %d %s", errno, strerror(errno));
}
option = 10;
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPINTVL, &option, sizeof(option)) < 0) {
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive interval %d %s", errno, strerror(errno));
}
option = 6;
if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPCNT, &option, sizeof(option)) < 0) {
logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive probes %d %s", errno, strerror(errno));
}
readstart = 0;
}