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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
/*
* Copyright (C) 2005-2009 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
/** \file crypt.c openssl-based RSA encryption/decryption routines */
#include "para.h"
#include "error.h"
#include "string.h"
#include "crypt.h"
static EVP_PKEY *load_key(const char *file, int private)
{
BIO *key;
EVP_PKEY *pkey = NULL;
key = BIO_new(BIO_s_file());
if (!key)
return NULL;
if (BIO_read_filename(key, file) > 0) {
if (private == LOAD_PRIVATE_KEY)
pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
else
pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
}
BIO_free(key);
return pkey;
}
/**
* read an RSA key from a file
*
* \param key_file the file containing the key
* \param rsa RSA structure is returned here
* \param private if non-zero, read the private key, otherwise the public key
*
* \return The size of the RSA key on success, negative on errors.
*
* \sa openssl(1), rsa(1).
*/
int get_rsa_key(char *key_file, RSA **rsa, int private)
{
EVP_PKEY *key = load_key(key_file, private);
if (!key)
return (private == LOAD_PRIVATE_KEY)? -E_PRIVATE_KEY
: -E_PUBLIC_KEY;
*rsa = EVP_PKEY_get1_RSA(key);
EVP_PKEY_free(key);
if (!*rsa)
return -E_RSA;
return RSA_size(*rsa);
}
/**
* free an RSA structure
*
* \param rsa pointer to the RSA struct to free
*
* This must be called for any key obtained by get_rsa_key().
*/
void rsa_free(RSA *rsa)
{
if (rsa)
RSA_free(rsa);
}
/**
* decrypt a buffer using an RSA key
*
* \param key_file full path of the rsa key
* \param outbuf the output buffer
* \param inbuf the encrypted input buffer
* \param rsa_inlen the length of \a inbuf
*
* The \a outbuf must be large enough to hold at least \a rsa_inlen bytes.
*
* \return The size of the recovered plaintext on success, negative on errors.
*
* \sa RSA_private_decrypt(3)
**/
int para_decrypt_buffer(char *key_file, unsigned char *outbuf, unsigned char *inbuf,
unsigned rsa_inlen)
{
RSA *rsa;
int ret, inlen = rsa_inlen;
if (inlen < 0)
return -E_RSA;
ret = get_rsa_key(key_file, &rsa, LOAD_PRIVATE_KEY);
if (ret < 0)
return ret;
ret = RSA_private_decrypt(inlen, inbuf, outbuf, rsa, RSA_PKCS1_PADDING);
rsa_free(rsa);
return (ret > 0)? ret : -E_DECRYPT;
}
/**
* decrypt the challenge number sent by para_server
*
* \param key_file full path of the rsa key
* \param challenge_nr result is stored here
* \param inbuf the input buffer
* \param rsa_inlen the length of \a inbuf
*
* \return positive on success, negative on errors
*
* \sa para_decrypt_buffer()
*/
int para_decrypt_challenge(char *key_file, long unsigned *challenge_nr,
unsigned char *inbuf, unsigned rsa_inlen)
{
unsigned char *rsa_out = OPENSSL_malloc(rsa_inlen + 1);
int ret = para_decrypt_buffer(key_file, rsa_out, inbuf, rsa_inlen);
if (ret >= 0) {
rsa_out[ret] = '\0';
ret = sscanf((char *)rsa_out, "%lu", challenge_nr) == 1?
1 : -E_CHALLENGE;
}
OPENSSL_free(rsa_out);
return ret;
}
/**
* encrypt a buffer using an RSA key
*
* \param rsa: public rsa key
* \param inbuf the input buffer
* \param len the length of \a inbuf
* \param outbuf the output buffer
*
* \return The size of the encrypted data on success, negative on errors
*
* \sa RSA_public_encrypt(3)
*/
int para_encrypt_buffer(RSA *rsa, unsigned char *inbuf,
unsigned len, unsigned char *outbuf)
{
int ret, flen = len; /* RSA_public_encrypt expects a signed int */
if (flen < 0)
return -E_ENCRYPT;
ret = RSA_public_encrypt(flen, inbuf, outbuf, rsa, RSA_PKCS1_PADDING);
return ret < 0? -E_ENCRYPT : ret;
}
/**
* encrypt the given challenge number
*
* \param rsa: public rsa key
* \param challenge_nr the number to be encrypted
* \param outbuf the output buffer
*
* \a outbuf must be at least 64 bytes long
*
* \return The size of the encrypted data on success, negative on errors
*
* \sa para_encrypt_buffer()
*
*/
int para_encrypt_challenge(RSA* rsa, long unsigned challenge_nr,
unsigned char *outbuf)
{
unsigned char *inbuf = (unsigned char*) make_message("%lu", challenge_nr);
int ret = para_encrypt_buffer(rsa, inbuf, strlen((char *)inbuf), outbuf);
free(inbuf);
return ret;
}
|