/* * 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); }