// The contents of this file are subject to the BOINC Public License // Version 1.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://boinc.berkeley.edu/license_1.0.txt // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is the Berkeley Open Infrastructure for Network Computing. // // The Initial Developer of the Original Code is the SETI@home project. // Portions created by the SETI@home project are Copyright (C) 2002 // University of California at Berkeley. All Rights Reserved. // // Contributor(s): // #ifdef _WIN32 #include "boinc_win.h" #endif #ifndef _WIN32 #include #include #include #if HAVE_MALLOC_H #include #endif #endif #include "md5_file.h" #include "error_numbers.h" #include "crypt.h" #ifdef _USING_FCGI_ #include "fcgi_stdio.h" #endif // NOTE: the fast CGI I/O library doesn't have fscanf(), // so some of the following have been modified to use // fgets() and sscanf() instead // write some data in hex notation. // NOTE: since length may not be known to the reader, // we follow the data with a non-hex character '.' // int print_hex_data(FILE* f, DATA_BLOCK& x) { unsigned int i; for (i=0; ibits); len = size - sizeof(key->bits); x.data = key->data; x.len = len; return print_hex_data(f, x); } int scan_key_hex(FILE* f, KEY* key, int size) { int len, i, n; int num_bits; #if _USING_FCGI_ #if 0 char *p, buf[256]; int j = 0, b; fgets(buf, 256, f); sscanf(buf, "%d", &num_bits); key->bits = num_bits; len = size - sizeof(key->bits); while (1) { p = fgets(buf, 256, f); if (!p) return ERR_GETS; n = strlen(p)/2; if (n == 0) break; for (i=0; i= len) return ERR_SCANF; key->data[j++] = b; } } fgets(buf, size, f); sscanf(buf, "."); #endif #else fscanf(f, "%d", &num_bits); key->bits = num_bits; len = size - sizeof(key->bits); for (i=0; idata[i] = n; } fscanf(f, "."); #endif return 0; } // parse a text-encoded key from a memory buffer // int sscan_key_hex(char* buf, KEY* key, int size) { int n, retval,num_bits; DATA_BLOCK db; //fprintf(stderr, "buf = %s\n", buf); n = sscanf(buf, "%d", &num_bits); key->bits = num_bits; //key->bits is a short //fprintf(stderr, "key->bits = %d\n", key->bits); if (n != 1) return ERR_SCANF; buf = strchr(buf, '\n'); if (!buf) return ERR_STRCHR; buf += 1; db.data = key->data; db.len = size - sizeof(key->bits); //huh??? retval = sscan_hex_data(buf, db); return retval; } // encrypt some data. // The amount encrypted may be less than what's supplied. // The output buffer must be at least MIN_OUT_BUFFER_SIZE. // The output block must be decrypted in its entirety. // int encrypt_private( R_RSA_PRIVATE_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out, int& nbytes_encrypted ) { int retval, n, modulus_len; modulus_len = (key.bits+7)/8; n = in.len; if (n >= modulus_len-11) { n = modulus_len-11; } retval = RSAPrivateEncrypt(out.data, &out.len, in.data, n, &key); if (retval ) return retval; nbytes_encrypted = retval; return 0; } int decrypt_public(R_RSA_PUBLIC_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out) { return RSAPublicDecrypt(out.data, &out.len, in.data, in.len, &key); } int sign_file(char* path, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) { char md5_buf[MD5_LEN]; double file_length; DATA_BLOCK in_block; int retval, n; retval = md5_file(path, md5_buf, file_length); if (retval) return retval; in_block.data = (unsigned char*)md5_buf; in_block.len = strlen(md5_buf); retval = encrypt_private(key, in_block, signature, n); if (retval) return retval; return 0; } int sign_block(DATA_BLOCK& data_block, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) { char md5_buf[MD5_LEN]; int retval, n; DATA_BLOCK in_block; md5_block(data_block.data, data_block.len, md5_buf); in_block.data = (unsigned char*)md5_buf; in_block.len = strlen(md5_buf); retval = encrypt_private(key, in_block, signature, n); if (retval) { printf("sign_block: encrypt_private returned %d\n", retval); return retval; } return 0; } int verify_file( char* path, R_RSA_PUBLIC_KEY& key, DATA_BLOCK& signature, bool& answer ) { char md5_buf[MD5_LEN], clear_buf[MD5_LEN]; double file_length; int n, retval; DATA_BLOCK clear_signature; retval = md5_file(path, md5_buf, file_length); if (retval) { fprintf(stderr, "error: verify_file: md5_file error %d\n", retval); return retval; } n = strlen(md5_buf); clear_signature.data = (unsigned char*)clear_buf; clear_signature.len = MD5_LEN; retval = decrypt_public(key, signature, clear_signature); if (retval) { fprintf(stderr, "error: verify_file: decrypt_public error %d\n", retval); return retval; } answer = !strncmp(md5_buf, clear_buf, n); return 0; } int verify_file2( char* path, char* signature_text, char* key_text, bool& answer ) { R_RSA_PUBLIC_KEY key; unsigned char signature_buf[SIGNATURE_SIZE_BINARY]; int retval; DATA_BLOCK signature; retval = sscan_key_hex(key_text, (KEY*)&key, sizeof(key)); if (retval) { fprintf(stderr, "error: verify_file2: sscan_key_hex did not work\n"); return retval; } signature.data = signature_buf; signature.len = sizeof(signature_buf); retval = sscan_hex_data(signature_text, signature); if (retval) return retval; return verify_file(path, key, signature, answer); } // verify, where both text and signature are char strings // int verify_string( char* text, char* signature_text, R_RSA_PUBLIC_KEY& key, bool& answer ) { char md5_buf[MD5_LEN]; unsigned char signature_buf[SIGNATURE_SIZE_BINARY]; char clear_buf[MD5_LEN]; int retval, n; DATA_BLOCK signature, clear_signature; retval = md5_block((unsigned char*)text, strlen(text), md5_buf); if (retval) return retval; n = strlen(md5_buf); signature.data = signature_buf; signature.len = sizeof(signature_buf); retval = sscan_hex_data(signature_text, signature); if (retval) return retval; clear_signature.data = (unsigned char*)clear_buf; clear_signature.len = 256; retval = decrypt_public(key, signature, clear_signature); if (retval) return retval; answer = !strncmp(md5_buf, clear_buf, n); return 0; } // Same, where public key is also encoded as text // int verify_string2( char* text, char* signature_text, char* key_text, bool& answer ) { R_RSA_PUBLIC_KEY key; int retval; retval = sscan_key_hex(key_text, (KEY*)&key, sizeof(key)); if (retval) return retval; return verify_string(text, signature_text, key, answer); } int read_key_file(char* keyfile, R_RSA_PRIVATE_KEY& key) { int retval; FILE* fkey = fopen(keyfile, "r"); if (!fkey) { fprintf(stderr, "can't open key file (%s)\n", keyfile); return ERR_FOPEN; } retval = scan_key_hex(fkey, (KEY*)&key, sizeof(key)); fclose(fkey); if (retval) { fprintf(stderr, "can't parse key\n"); return retval; } return 0; }