mirror of
https://github.com/libretro/parallel-gx2.git
synced 2026-11-07 04:25:58 -10:00
The core builds with a static Makefile (Makefile + Makefile.common) in the manner of the other ParaLLEl cores, for every target .gitlab-ci.yml has: Linux x86_64/aarch64, Windows (MinGW, native or cross), macOS, iOS, tvOS, Android arm64/x86_64 and webOS. CMake, vcpkg and their overlay ports are gone; the libraries the core needs are submodules built with it (fmt 12.1.0, glm 1.0.1, glslang 15.1.0, libusb 1.0.29, pugixml 1.15, zlib 1.3.1, zstd 1.5.7), with the generated files and the graphic packs produced by the Makefile itself (tools/pack_graphic_packs.c), and a precompiled header for gcc and clang. The core is renamed parallel_gx2 (parallel_gx2_libretro.info, library name "ParaLLEl GX2"). HTTP and TLS go through RetroArch's libretro-common (net_http with the per-request TLS settings, the built-in TLS client, x509, the hashes and the KDF) in place of libcurl, OpenSSL and mbedTLS: dependencies/curl-compat is the small libcurl API nlibcurl and napi use, on one transfer thread with lock-free submission and per-handle event queues, with its own tests against local HTTP and TLS servers, plain and under ASan/UBSan and TSan, in both CIs. The libretro-common files are plain copies from RetroArch. boost is replaced by the few headers the core uses (boost-compat), and the CI files build with the Makefile.
297 lines
12 KiB
C
297 lines
12 KiB
C
/* Copyright (C) 2026 The RetroArch team
|
|
*
|
|
* ---------------------------------------------------------------------------------------
|
|
* The following license statement only applies to this file (pk.h).
|
|
* ---------------------------------------------------------------------------------------
|
|
*
|
|
* 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 _LIBRETRO_CRYPTO_PK_H
|
|
#define _LIBRETRO_CRYPTO_PK_H
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#include <retro_common_api.h>
|
|
|
|
RETRO_BEGIN_DECLS
|
|
|
|
/* Public-key side of the cleanroom stack: fixed-width bignum, RSA
|
|
* PKCS#1 v1.5 signing and verification, P-256 / P-384 ECDH and ECDSA
|
|
* verification, X25519, and ECDH / ECDSA on sect233r1. */
|
|
|
|
/* Fixed-width multi-precision arithmetic for the public-key code:
|
|
* little-endian arrays of bn_word, every operand of one call the
|
|
* same length k, Montgomery multiplication with double-word products. There
|
|
* is no dynamic sizing and no allocation in here; callers pick k from
|
|
* the modulus and keep the working storage themselves (on the heap
|
|
* for RSA - see rsa.c - since a 4096-bit operand is 512 bytes). */
|
|
|
|
/* 64-bit limbs with 128-bit products wherever the compiler has them
|
|
* (GCC and Clang on 64-bit targets): a Montgomery multiplication is
|
|
* a quarter of the word products of the 32-bit form. Everywhere else,
|
|
* 32-bit limbs with 64-bit products, which is plain C89. */
|
|
#if defined(__SIZEOF_INT128__) && !defined(BN_WORD_32)
|
|
typedef uint64_t bn_word;
|
|
__extension__ typedef unsigned __int128 bn_dword;
|
|
#define BN_WORD_BITS 64
|
|
#else
|
|
typedef uint32_t bn_word;
|
|
typedef uint64_t bn_dword;
|
|
#define BN_WORD_BITS 32
|
|
#endif
|
|
#define BN_WORD_BYTES (BN_WORD_BITS / 8)
|
|
|
|
/* 4096-bit RSA is the largest key in any CA bundle this tree ships. */
|
|
#define BN_MAX_WORDS (4096 / BN_WORD_BITS)
|
|
|
|
/* Words of scratch bn_mont_mul() and bn_mont_sqr() need for length k. */
|
|
#define BN_MONT_TMP_WORDS(k) (2 * (k) + 2)
|
|
|
|
void bn_from_be(bn_word *r, unsigned k, const uint8_t *in, size_t len);
|
|
void bn_to_be(uint8_t *out, size_t len, const bn_word *a, unsigned k);
|
|
void bn_zero(bn_word *r, unsigned k);
|
|
void bn_copy(bn_word *r, const bn_word *a, unsigned k);
|
|
int bn_is_zero(const bn_word *a, unsigned k);
|
|
/* -1, 0, 1; constant time in k. */
|
|
int bn_cmp(const bn_word *a, const bn_word *b, unsigned k);
|
|
bn_word bn_add(bn_word *r, const bn_word *a, const bn_word *b, unsigned k);
|
|
bn_word bn_sub(bn_word *r, const bn_word *a, const bn_word *b, unsigned k);
|
|
/* r = a + b mod m and r = a - b mod m, for a, b < m. */
|
|
void bn_mod_add(bn_word *r, const bn_word *a, const bn_word *b,
|
|
const bn_word *m, unsigned k);
|
|
void bn_mod_sub(bn_word *r, const bn_word *a, const bn_word *b,
|
|
const bn_word *m, unsigned k);
|
|
/* r = bit ? a : b, without branching on bit. */
|
|
void bn_select(bn_word *r, bn_word bit, const bn_word *a,
|
|
const bn_word *b, unsigned k);
|
|
/* Highest set bit + 1, 0 for zero. */
|
|
unsigned bn_bit_length(const bn_word *a, unsigned k);
|
|
unsigned bn_get_bit(const bn_word *a, unsigned i);
|
|
|
|
/* Montgomery machinery, R = 2^(BN_WORD_BITS * k). */
|
|
bn_word bn_mont_n0(const bn_word *m);
|
|
/* r2 = R^2 mod m. Only needs m odd. */
|
|
void bn_mont_r2(bn_word *r2, const bn_word *m, unsigned k);
|
|
/* r = a * b * R^-1 mod m, for a, b < m; @tmp has BN_MONT_TMP_WORDS(k). */
|
|
void bn_mont_mul(bn_word *r, const bn_word *a, const bn_word *b,
|
|
const bn_word *m, bn_word n0, unsigned k, bn_word *tmp);
|
|
/* r = a * a * R^-1 mod m: the off-diagonal products once, doubled,
|
|
* which is what an exponentiation spends most of its time on. */
|
|
void bn_mont_sqr(bn_word *r, const bn_word *a,
|
|
const bn_word *m, bn_word n0, unsigned k, bn_word *tmp);
|
|
/* r = a * b mod m (plain domain), through @r2 = R^2 mod m. */
|
|
void bn_mod_mul(bn_word *r, const bn_word *a, const bn_word *b,
|
|
const bn_word *m, const bn_word *r2, bn_word n0, unsigned k,
|
|
bn_word *tmp);
|
|
/* r = base^exp mod m, plain domain. exp has ek words. Left-to-right
|
|
* binary; exponents here are public (RSA e, curve orders). @work has
|
|
* 3k + BN_MONT_TMP_WORDS(k) words. */
|
|
void bn_mod_exp(bn_word *r, const bn_word *base,
|
|
const bn_word *exp, unsigned ek,
|
|
const bn_word *m, const bn_word *r2, bn_word n0, unsigned k,
|
|
bn_word *work);
|
|
|
|
/* RSASSA-PKCS1-v1_5 signature verification (RFC 8017 8.2.2), the
|
|
* only RSA operation a TLS client with a CA bundle needs. Public-key
|
|
* operands only, so nothing here is secret. */
|
|
|
|
enum rsa_hash
|
|
{
|
|
RSA_HASH_SHA256 = 0,
|
|
RSA_HASH_SHA384 = 1,
|
|
RSA_HASH_SHA512 = 2,
|
|
RSA_HASH_SHA1 = 3,
|
|
/* MD5 || SHA-1, 36 octets, without a DigestInfo (TLS 1.0, 1.1) */
|
|
RSA_HASH_MD5_SHA1 = 4
|
|
};
|
|
|
|
/**
|
|
* rsa_pkcs1_verify:
|
|
* @n, @n_len : Modulus, big-endian, up to 512 octets (4096 bits).
|
|
* @e, @e_len : Public exponent, big-endian.
|
|
* @digest : The already computed hash of the signed data,
|
|
* 32/48/64 octets for @hash.
|
|
* @sig, @sig_len : Signature, big-endian, @sig_len == the modulus
|
|
* length after leading zeros.
|
|
*
|
|
* Returns: 0 when the signature is valid, -1 otherwise (bad key or
|
|
* parameter, or verification failure; the two are not distinguished
|
|
* on purpose).
|
|
**/
|
|
int rsa_pkcs1_verify(const uint8_t *n, size_t n_len,
|
|
const uint8_t *e, size_t e_len,
|
|
enum rsa_hash hash, const uint8_t *digest, size_t digest_len,
|
|
const uint8_t *sig, size_t sig_len);
|
|
|
|
/**
|
|
* rsa_pkcs1_encrypt:
|
|
* RSAES-PKCS1-v1_5 encryption (RFC 8017 7.2.1) under a public key, as
|
|
* a TLS RSA key exchange sends its premaster secret.
|
|
* @out, @out_len : Out, @out_len == the modulus length.
|
|
*
|
|
* Returns: 0 on success, -1 on a bad key, a message longer than the
|
|
* modulus allows, or no randomness.
|
|
**/
|
|
int rsa_pkcs1_encrypt(const uint8_t *n, size_t n_len,
|
|
const uint8_t *e, size_t e_len,
|
|
const uint8_t *msg, size_t msg_len, uint8_t *out, size_t out_len);
|
|
|
|
/* An RSA private key, every member a big-endian integer pointing into
|
|
* memory the caller keeps (x509_rsa_private_key_parse() fills it from
|
|
* DER). Leading zero octets are allowed. */
|
|
struct rsa_private_key
|
|
{
|
|
const uint8_t *n; size_t n_len;
|
|
const uint8_t *e; size_t e_len;
|
|
const uint8_t *d; size_t d_len;
|
|
const uint8_t *p; size_t p_len;
|
|
const uint8_t *q; size_t q_len;
|
|
const uint8_t *dp; size_t dp_len; /* d mod (p - 1) */
|
|
const uint8_t *dq; size_t dq_len; /* d mod (q - 1) */
|
|
const uint8_t *qi; size_t qi_len; /* q^-1 mod p */
|
|
};
|
|
|
|
/**
|
|
* rsa_pkcs1_sign:
|
|
* RSASSA-PKCS1-v1_5 signature (RFC 8017 8.2.1) over an already
|
|
* computed @digest, through the CRT with an exponentiation whose
|
|
* operations and memory accesses do not depend on the key. p and q
|
|
* must have the same number of words. The signature is checked with
|
|
* the public exponent before it is returned.
|
|
* @sig, @sig_len : Out, @sig_len == the modulus length.
|
|
*
|
|
* Returns: 0 on success, -1 on a bad or inconsistent key or a
|
|
* parameter out of range (@sig is then zeroed).
|
|
**/
|
|
int rsa_pkcs1_sign(const struct rsa_private_key *key,
|
|
enum rsa_hash hash, const uint8_t *digest, size_t digest_len,
|
|
uint8_t *sig, size_t sig_len);
|
|
|
|
/**
|
|
* rsa_pss_verify:
|
|
* RSASSA-PSS with MGF1 over the same hash and a salt of the hash
|
|
* length (TLS 1.3 rsa_pss_rsae_*). Arguments as rsa_pkcs1_verify().
|
|
**/
|
|
int rsa_pss_verify(const uint8_t *n, size_t n_len,
|
|
const uint8_t *e, size_t e_len,
|
|
enum rsa_hash hash, const uint8_t *digest, size_t digest_len,
|
|
const uint8_t *sig, size_t sig_len);
|
|
|
|
/**
|
|
* x25519:
|
|
* RFC 7748 X25519: @out = @scalar * @u_le, all 32 octets little-endian
|
|
* as on the wire; the scalar is clamped here. Returns -1 when the
|
|
* result is the all-zero point (a low-order input), 0 otherwise.
|
|
* x25519_base() uses the base point 9.
|
|
**/
|
|
int x25519(uint8_t *out, const uint8_t *scalar, const uint8_t *u_le);
|
|
int x25519_base(uint8_t *out, const uint8_t *scalar);
|
|
|
|
/* NIST P-256 (secp256r1): ECDH for the TLS key exchange and ECDSA
|
|
* signature verification for certificates. Points on the wire are
|
|
* uncompressed SEC 1 encodings, 0x04 || X || Y. Field and scalar
|
|
* arithmetic run through bn's Montgomery machinery at k = 8. */
|
|
|
|
#define P256_SCALAR_SIZE 32
|
|
#define P256_POINT_SIZE 65
|
|
|
|
/**
|
|
* p256_keygen:
|
|
* @priv : 32 random octets; rejected when 0 or >= n, so
|
|
* the caller draws again (probability ~2^-32).
|
|
* @pub : 65 octets out.
|
|
*
|
|
* Returns: 0 on success, -1 on an unusable scalar.
|
|
**/
|
|
int p256_keygen(const uint8_t *priv, uint8_t *pub);
|
|
|
|
/**
|
|
* p256_ecdh:
|
|
* @shared : 32 octets out, the x coordinate.
|
|
*
|
|
* Validates @peer (on the curve, coordinates in range) first.
|
|
*
|
|
* Returns: 0 on success, -1 on a bad key or a result at infinity.
|
|
**/
|
|
int p256_ecdh(const uint8_t *priv, const uint8_t *peer, uint8_t *shared);
|
|
|
|
/**
|
|
* p256_ecdsa_verify:
|
|
* @digest : Message hash; the leftmost 32 octets are used
|
|
* (FIPS 186-4 6.4), shorter digests are allowed.
|
|
* @r, @s : 32 octets each, big-endian.
|
|
*
|
|
* Returns: 0 when valid, -1 otherwise.
|
|
**/
|
|
int p256_ecdsa_verify(const uint8_t *pub,
|
|
const uint8_t *digest, size_t digest_len,
|
|
const uint8_t *r, const uint8_t *s);
|
|
|
|
/* NIST P-384 (secp384r1), the same operations on 48-octet scalars and
|
|
* 97-octet points. Needed for the CA roots that carry P-384 keys. */
|
|
#define P384_SCALAR_SIZE 48
|
|
#define P384_POINT_SIZE 97
|
|
|
|
int p384_keygen(const uint8_t *priv, uint8_t *pub);
|
|
int p384_ecdh(const uint8_t *priv, const uint8_t *peer, uint8_t *shared);
|
|
int p384_ecdsa_verify(const uint8_t *pub,
|
|
const uint8_t *digest, size_t digest_len,
|
|
const uint8_t *r, const uint8_t *s);
|
|
|
|
/* SECG sect233r1 (NIST B-233), the binary curve of the Nintendo DSi,
|
|
* Wii, Wii U and 3DS certificates and tickets. Scalars, coordinates and
|
|
* signature halves are 30 octets big-endian; points are 0x04 || X || Y.
|
|
* A private key may be any 30 octets: it is reduced mod n, and rejected
|
|
* only when that leaves 0. Every operation with a private key runs a
|
|
* fixed-length Montgomery ladder. */
|
|
#define B233_SCALAR_SIZE 30
|
|
#define B233_POINT_SIZE 61
|
|
|
|
int b233_keygen(const uint8_t *priv, uint8_t *pub);
|
|
|
|
/**
|
|
* b233_ecdh:
|
|
* @shared : 30 octets out, the x coordinate.
|
|
*
|
|
* Validates @peer (on the curve, in the subgroup of order n) first.
|
|
*
|
|
* Returns: 0 on success, -1 on a bad key.
|
|
**/
|
|
int b233_ecdh(const uint8_t *priv, const uint8_t *peer, uint8_t *shared);
|
|
|
|
/**
|
|
* b233_ecdsa_sign:
|
|
* @digest : Message hash; its leftmost 233 bits are used.
|
|
* @r, @s : 30 octets each, out.
|
|
*
|
|
* The nonce is deterministic, RFC 6979 with HMAC-SHA256.
|
|
*
|
|
* Returns: 0 on success, -1 on an unusable private key.
|
|
**/
|
|
int b233_ecdsa_sign(const uint8_t *priv,
|
|
const uint8_t *digest, size_t digest_len,
|
|
uint8_t *r, uint8_t *s);
|
|
|
|
int b233_ecdsa_verify(const uint8_t *pub,
|
|
const uint8_t *digest, size_t digest_len,
|
|
const uint8_t *r, const uint8_t *s);
|
|
|
|
RETRO_END_DECLS
|
|
|
|
#endif
|