/*
* RabbitSign - Tools for signing TI graphing calculator software
* Copyright (C) 2009 Benjamin Moody
*
* 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 the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include "rabbitsign.h"
#include "internal.h"
#define VALIDATION_EXPONENT 17
/*
* Calculate the RSA signing exponent.
*
* The validation exponent, e, is 17 for all TI-related RSA
* signatures. The signing exponent, d, depends on n, and is
* calculated so that e * d === 1 (mod (p-1)(q-1)).
*
* (This means that for any number x,
*
* x^(e * d) = x * x^[k0 * (p-1)] === x * 1 (mod p),
*
* and likewise
*
* x^(e * d) = x * x^[k1 * (q-1)] === x * 1 (mod q).
*
* Therefore (Chinese remainder theorem) x^(e * d) === x (mod n).
*
* Note that there is no way of calculating d without knowing the
* factors of n; this is a key point in the security of RSA.)
*/
static int get_exponent(mpz_t res, /* mpz to store result */
int e, /* validation exponent */
const mpz_t p, /* first factor */
const mpz_t q) /* second fatctor */
{
mpz_t a, b;
mpz_init(a);
mpz_init(b);
mpz_sub_ui(a, p, 1);
mpz_sub_ui(b, q, 1);
mpz_mul(a, a, b);
mpz_set_ui(b, e);
mpz_gcdext(b, res, NULL, b, a);
if (mpz_cmp_ui(b, 1)) {
mpz_clear(a);
mpz_clear(b);
return RS_ERR_UNSUITABLE_RSA_KEY;
}
mpz_mod(res, res, a);
mpz_clear(a);
mpz_clear(b);
return RS_SUCCESS;
}
/*
* Compute an RSA signature.
*
* This is simply the hash raised to the d-th power mod n (where d is
* defined above.)
*/
int rs_sign_rsa(mpz_t res, /* mpz to store signature */
const mpz_t hash, /* MD5 hash of app */
RSKey* key) /* key structure */
{
if (!mpz_sgn(key->n)) {
rs_error(key, NULL, "unable to sign: public key missing");
return RS_ERR_MISSING_PUBLIC_KEY;
}
if (!mpz_sgn(key->d)) {
if (!mpz_sgn(key->p) || !mpz_sgn(key->q)) {
rs_error(key, NULL, "unable to sign: private key missing");
return RS_ERR_MISSING_PRIVATE_KEY;
}
if (get_exponent(key->d, VALIDATION_EXPONENT, key->p, key->q)) {
rs_error(key, NULL, "unable to sign: unsuitable key");
return RS_ERR_UNSUITABLE_RSA_KEY;
}
}
mpz_powm(res, hash, key->d, key->n);
return RS_SUCCESS;
}
/*
* Check that the given RSA signature is valid.
*
* To do this, we raise the signature to the 17th power mod n, and see
* if it matches the hash.
*/
int rs_validate_rsa(const mpz_t sig, /* purported signature of app */
const mpz_t hash, /* MD5 hash of app */
const RSKey* key) /* key structure */
{
mpz_t e, m;
int result;
if (!mpz_sgn(key->n)) {
rs_error(key, NULL, "unable to validate: public key missing");
return RS_ERR_MISSING_PUBLIC_KEY;
}
mpz_init(e);
mpz_init(m);
mpz_set_ui(e, VALIDATION_EXPONENT);
mpz_powm(m, sig, e, key->n);
result = mpz_cmp(hash, m);
mpz_clear(e);
mpz_clear(m);
return (result ? RS_SIGNATURE_INCORRECT : RS_SUCCESS);
}