| 55 |
#include <winsock.h> |
#include <winsock.h> |
| 56 |
#endif /* INET6 */ |
#endif /* INET6 */ |
| 57 |
|
|
| 58 |
|
#include <Lmcons.h> |
| 59 |
|
|
| 60 |
|
// include OpenSSL header file |
| 61 |
#include <openssl/opensslv.h> |
#include <openssl/opensslv.h> |
| 62 |
|
#include <openssl/evp.h> |
| 63 |
|
#include <openssl/rsa.h> |
| 64 |
|
#include <openssl/dsa.h> |
| 65 |
|
#include <openssl/bn.h> |
| 66 |
|
#include <openssl/pem.h> |
| 67 |
|
#include <openssl/rand.h> |
| 68 |
|
#include <openssl/rc4.h> |
| 69 |
|
|
| 70 |
|
#include "buffer.h" |
| 71 |
|
#include "cipher.h" |
| 72 |
|
|
| 73 |
#define MATCH_STR(s, o) _strnicmp((s), (o), NUM_ELEM(o) - 1) |
#define MATCH_STR(s, o) _strnicmp((s), (o), NUM_ELEM(o) - 1) |
| 74 |
|
|
| 1393 |
/* inserts before ID_SETUP_TCPIP */ |
/* inserts before ID_SETUP_TCPIP */ |
| 1394 |
insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU, |
insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU, |
| 1395 |
"SSH F&orwarding..."); |
"SSH F&orwarding..."); |
| 1396 |
|
|
| 1397 |
|
insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHKEYGENMENU, |
| 1398 |
|
"SSH KeyGenerator..."); |
| 1399 |
} |
} |
| 1400 |
|
|
| 1401 |
static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg) |
static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg) |
| 1946 |
return FALSE; |
return FALSE; |
| 1947 |
} |
} |
| 1948 |
|
|
| 1949 |
|
|
| 1950 |
|
// |
| 1951 |
|
// SSH key generator dialog (2005.4.10 yutaka) |
| 1952 |
|
// |
| 1953 |
|
|
| 1954 |
|
typedef struct { |
| 1955 |
|
RSA *rsa; |
| 1956 |
|
DSA *dsa; |
| 1957 |
|
} ssh_private_key_t; |
| 1958 |
|
|
| 1959 |
|
static ssh_private_key_t private_key = {NULL, NULL}; |
| 1960 |
|
|
| 1961 |
|
typedef struct { |
| 1962 |
|
RSA *rsa; |
| 1963 |
|
DSA *dsa; |
| 1964 |
|
} ssh_public_key_t; |
| 1965 |
|
|
| 1966 |
|
static ssh_public_key_t public_key = {NULL, NULL};; |
| 1967 |
|
|
| 1968 |
|
static void free_ssh_key(void) |
| 1969 |
|
{ |
| 1970 |
|
// DSA_free(), RSA_free()にNULLを渡しても問題はなし。 |
| 1971 |
|
DSA_free(private_key.dsa); |
| 1972 |
|
private_key.dsa = NULL; |
| 1973 |
|
DSA_free(public_key.dsa); |
| 1974 |
|
public_key.dsa = NULL; |
| 1975 |
|
|
| 1976 |
|
RSA_free(private_key.rsa); |
| 1977 |
|
private_key.rsa = NULL; |
| 1978 |
|
RSA_free(public_key.rsa); |
| 1979 |
|
public_key.rsa = NULL; |
| 1980 |
|
} |
| 1981 |
|
|
| 1982 |
|
|
| 1983 |
|
static BOOL generate_ssh_key(enum hostkey_type type) |
| 1984 |
|
{ |
| 1985 |
|
int bits = 1024; |
| 1986 |
|
|
| 1987 |
|
// if SSH key already is generated, should free the resource. |
| 1988 |
|
free_ssh_key(); |
| 1989 |
|
|
| 1990 |
|
if (type == KEY_RSA1 || type == KEY_RSA) { |
| 1991 |
|
RSA *priv = NULL; |
| 1992 |
|
RSA *pub = NULL; |
| 1993 |
|
|
| 1994 |
|
// private key |
| 1995 |
|
priv = RSA_generate_key(bits, 35, NULL, NULL); |
| 1996 |
|
if (priv == NULL) |
| 1997 |
|
goto error; |
| 1998 |
|
private_key.rsa = priv; |
| 1999 |
|
|
| 2000 |
|
// public key |
| 2001 |
|
pub = RSA_new(); |
| 2002 |
|
pub->n = BN_new(); |
| 2003 |
|
pub->e = BN_new(); |
| 2004 |
|
if (pub->n == NULL || pub->e == NULL) { |
| 2005 |
|
RSA_free(pub); |
| 2006 |
|
goto error; |
| 2007 |
|
} |
| 2008 |
|
|
| 2009 |
|
BN_copy(pub->n, priv->n); |
| 2010 |
|
BN_copy(pub->e, priv->e); |
| 2011 |
|
public_key.rsa = pub; |
| 2012 |
|
|
| 2013 |
|
} else if (type == KEY_DSA) { |
| 2014 |
|
DSA *priv = NULL; |
| 2015 |
|
DSA *pub = NULL; |
| 2016 |
|
|
| 2017 |
|
// private key |
| 2018 |
|
priv = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); |
| 2019 |
|
if (priv == NULL) |
| 2020 |
|
goto error; |
| 2021 |
|
if (!DSA_generate_key(priv)) { |
| 2022 |
|
// TODO: free 'priv'? |
| 2023 |
|
goto error; |
| 2024 |
|
} |
| 2025 |
|
private_key.dsa = priv; |
| 2026 |
|
|
| 2027 |
|
// public key |
| 2028 |
|
pub = DSA_new(); |
| 2029 |
|
if (pub == NULL) |
| 2030 |
|
goto error; |
| 2031 |
|
pub->p = BN_new(); |
| 2032 |
|
pub->q = BN_new(); |
| 2033 |
|
pub->g = BN_new(); |
| 2034 |
|
pub->pub_key = BN_new(); |
| 2035 |
|
if (pub->p == NULL || pub->q == NULL || pub->g == NULL || pub->pub_key == NULL) { |
| 2036 |
|
DSA_free(pub); |
| 2037 |
|
goto error; |
| 2038 |
|
} |
| 2039 |
|
|
| 2040 |
|
BN_copy(pub->p, priv->p); |
| 2041 |
|
BN_copy(pub->q, priv->q); |
| 2042 |
|
BN_copy(pub->g, priv->g); |
| 2043 |
|
BN_copy(pub->pub_key, priv->pub_key); |
| 2044 |
|
public_key.dsa = pub; |
| 2045 |
|
|
| 2046 |
|
} else { |
| 2047 |
|
goto error; |
| 2048 |
|
} |
| 2049 |
|
|
| 2050 |
|
return TRUE; |
| 2051 |
|
|
| 2052 |
|
error: |
| 2053 |
|
free_ssh_key(); |
| 2054 |
|
return FALSE; |
| 2055 |
|
} |
| 2056 |
|
|
| 2057 |
|
|
| 2058 |
|
// |
| 2059 |
|
// RC4 |
| 2060 |
|
// |
| 2061 |
|
|
| 2062 |
|
/* Size of key to use */ |
| 2063 |
|
#define SEED_SIZE 20 |
| 2064 |
|
|
| 2065 |
|
/* Number of bytes to reseed after */ |
| 2066 |
|
#define REKEY_BYTES (1 << 24) |
| 2067 |
|
|
| 2068 |
|
static int rc4_ready = 0; |
| 2069 |
|
static RC4_KEY rc4; |
| 2070 |
|
|
| 2071 |
|
static void seed_rng(void) |
| 2072 |
|
{ |
| 2073 |
|
if (RAND_status() != 1) |
| 2074 |
|
return; |
| 2075 |
|
} |
| 2076 |
|
|
| 2077 |
|
static void arc4random_stir(void) |
| 2078 |
|
{ |
| 2079 |
|
unsigned char rand_buf[SEED_SIZE]; |
| 2080 |
|
int i; |
| 2081 |
|
|
| 2082 |
|
memset(&rc4, 0, sizeof(rc4)); |
| 2083 |
|
if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) { |
| 2084 |
|
//fatal("Couldn't obtain random bytes (error %ld)", |
| 2085 |
|
// ERR_get_error()); |
| 2086 |
|
} |
| 2087 |
|
RC4_set_key(&rc4, sizeof(rand_buf), rand_buf); |
| 2088 |
|
|
| 2089 |
|
/* |
| 2090 |
|
* Discard early keystream, as per recommendations in: |
| 2091 |
|
* http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps |
| 2092 |
|
*/ |
| 2093 |
|
for(i = 0; i <= 256; i += sizeof(rand_buf)) |
| 2094 |
|
RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf); |
| 2095 |
|
|
| 2096 |
|
memset(rand_buf, 0, sizeof(rand_buf)); |
| 2097 |
|
|
| 2098 |
|
rc4_ready = REKEY_BYTES; |
| 2099 |
|
} |
| 2100 |
|
|
| 2101 |
|
static unsigned int arc4random(void) |
| 2102 |
|
{ |
| 2103 |
|
unsigned int r = 0; |
| 2104 |
|
static int first_time = 1; |
| 2105 |
|
|
| 2106 |
|
if (rc4_ready <= 0) { |
| 2107 |
|
if (first_time) { |
| 2108 |
|
seed_rng(); |
| 2109 |
|
} |
| 2110 |
|
first_time = 0; |
| 2111 |
|
arc4random_stir(); |
| 2112 |
|
} |
| 2113 |
|
|
| 2114 |
|
RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r); |
| 2115 |
|
|
| 2116 |
|
rc4_ready -= sizeof(r); |
| 2117 |
|
|
| 2118 |
|
return(r); |
| 2119 |
|
} |
| 2120 |
|
|
| 2121 |
|
// |
| 2122 |
|
// SSH1 3DES |
| 2123 |
|
// |
| 2124 |
|
/* |
| 2125 |
|
* This is used by SSH1: |
| 2126 |
|
* |
| 2127 |
|
* What kind of triple DES are these 2 routines? |
| 2128 |
|
* |
| 2129 |
|
* Why is there a redundant initialization vector? |
| 2130 |
|
* |
| 2131 |
|
* If only iv3 was used, then, this would till effect have been |
| 2132 |
|
* outer-cbc. However, there is also a private iv1 == iv2 which |
| 2133 |
|
* perhaps makes differential analysis easier. On the other hand, the |
| 2134 |
|
* private iv1 probably makes the CRC-32 attack ineffective. This is a |
| 2135 |
|
* result of that there is no longer any known iv1 to use when |
| 2136 |
|
* choosing the X block. |
| 2137 |
|
*/ |
| 2138 |
|
struct ssh1_3des_ctx |
| 2139 |
|
{ |
| 2140 |
|
EVP_CIPHER_CTX k1, k2, k3; |
| 2141 |
|
}; |
| 2142 |
|
|
| 2143 |
|
static int ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, int enc) |
| 2144 |
|
{ |
| 2145 |
|
struct ssh1_3des_ctx *c; |
| 2146 |
|
u_char *k1, *k2, *k3; |
| 2147 |
|
|
| 2148 |
|
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { |
| 2149 |
|
c = malloc(sizeof(*c)); |
| 2150 |
|
EVP_CIPHER_CTX_set_app_data(ctx, c); |
| 2151 |
|
} |
| 2152 |
|
if (key == NULL) |
| 2153 |
|
return (1); |
| 2154 |
|
if (enc == -1) |
| 2155 |
|
enc = ctx->encrypt; |
| 2156 |
|
k1 = k2 = k3 = (u_char *) key; |
| 2157 |
|
k2 += 8; |
| 2158 |
|
if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) { |
| 2159 |
|
if (enc) |
| 2160 |
|
k3 += 16; |
| 2161 |
|
else |
| 2162 |
|
k1 += 16; |
| 2163 |
|
} |
| 2164 |
|
EVP_CIPHER_CTX_init(&c->k1); |
| 2165 |
|
EVP_CIPHER_CTX_init(&c->k2); |
| 2166 |
|
EVP_CIPHER_CTX_init(&c->k3); |
| 2167 |
|
if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 || |
| 2168 |
|
EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 || |
| 2169 |
|
EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) { |
| 2170 |
|
memset(c, 0, sizeof(*c)); |
| 2171 |
|
free(c); |
| 2172 |
|
EVP_CIPHER_CTX_set_app_data(ctx, NULL); |
| 2173 |
|
return (0); |
| 2174 |
|
} |
| 2175 |
|
return (1); |
| 2176 |
|
} |
| 2177 |
|
|
| 2178 |
|
static int ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len) |
| 2179 |
|
{ |
| 2180 |
|
struct ssh1_3des_ctx *c; |
| 2181 |
|
|
| 2182 |
|
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { |
| 2183 |
|
//error("ssh1_3des_cbc: no context"); |
| 2184 |
|
return (0); |
| 2185 |
|
} |
| 2186 |
|
if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 || |
| 2187 |
|
EVP_Cipher(&c->k2, dest, dest, len) == 0 || |
| 2188 |
|
EVP_Cipher(&c->k3, dest, dest, len) == 0) |
| 2189 |
|
return (0); |
| 2190 |
|
return (1); |
| 2191 |
|
} |
| 2192 |
|
|
| 2193 |
|
static int ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx) |
| 2194 |
|
{ |
| 2195 |
|
struct ssh1_3des_ctx *c; |
| 2196 |
|
|
| 2197 |
|
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { |
| 2198 |
|
EVP_CIPHER_CTX_cleanup(&c->k1); |
| 2199 |
|
EVP_CIPHER_CTX_cleanup(&c->k2); |
| 2200 |
|
EVP_CIPHER_CTX_cleanup(&c->k3); |
| 2201 |
|
memset(c, 0, sizeof(*c)); |
| 2202 |
|
free(c); |
| 2203 |
|
EVP_CIPHER_CTX_set_app_data(ctx, NULL); |
| 2204 |
|
} |
| 2205 |
|
return (1); |
| 2206 |
|
} |
| 2207 |
|
|
| 2208 |
|
void ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len) |
| 2209 |
|
{ |
| 2210 |
|
struct ssh1_3des_ctx *c; |
| 2211 |
|
|
| 2212 |
|
if (len != 24) |
| 2213 |
|
//fatal("%s: bad 3des iv length: %d", __func__, len); |
| 2214 |
|
; |
| 2215 |
|
|
| 2216 |
|
if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) |
| 2217 |
|
//fatal("%s: no 3des context", __func__); |
| 2218 |
|
; |
| 2219 |
|
|
| 2220 |
|
if (doset) { |
| 2221 |
|
//debug3("%s: Installed 3DES IV", __func__); |
| 2222 |
|
memcpy(c->k1.iv, iv, 8); |
| 2223 |
|
memcpy(c->k2.iv, iv + 8, 8); |
| 2224 |
|
memcpy(c->k3.iv, iv + 16, 8); |
| 2225 |
|
} else { |
| 2226 |
|
//debug3("%s: Copying 3DES IV", __func__); |
| 2227 |
|
memcpy(iv, c->k1.iv, 8); |
| 2228 |
|
memcpy(iv + 8, c->k2.iv, 8); |
| 2229 |
|
memcpy(iv + 16, c->k3.iv, 8); |
| 2230 |
|
} |
| 2231 |
|
} |
| 2232 |
|
|
| 2233 |
|
const EVP_CIPHER *evp_ssh1_3des(void) |
| 2234 |
|
{ |
| 2235 |
|
static EVP_CIPHER ssh1_3des; |
| 2236 |
|
|
| 2237 |
|
memset(&ssh1_3des, 0, sizeof(EVP_CIPHER)); |
| 2238 |
|
ssh1_3des.nid = NID_undef; |
| 2239 |
|
ssh1_3des.block_size = 8; |
| 2240 |
|
ssh1_3des.iv_len = 0; |
| 2241 |
|
ssh1_3des.key_len = 16; |
| 2242 |
|
ssh1_3des.init = ssh1_3des_init; |
| 2243 |
|
ssh1_3des.cleanup = ssh1_3des_cleanup; |
| 2244 |
|
ssh1_3des.do_cipher = ssh1_3des_cbc; |
| 2245 |
|
ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH; |
| 2246 |
|
return (&ssh1_3des); |
| 2247 |
|
} |
| 2248 |
|
|
| 2249 |
|
static void ssh_make_comment(char *comment, int maxlen) |
| 2250 |
|
{ |
| 2251 |
|
char user[UNLEN + 1], host[128]; |
| 2252 |
|
DWORD dwSize; |
| 2253 |
|
WSADATA wsaData; |
| 2254 |
|
int ret; |
| 2255 |
|
|
| 2256 |
|
// get Windows logon user name |
| 2257 |
|
dwSize = sizeof(user); |
| 2258 |
|
if (GetUserName(user, &dwSize) == 0) { |
| 2259 |
|
strcpy(user, "yutaka"); |
| 2260 |
|
} |
| 2261 |
|
|
| 2262 |
|
// get local hostname (by WinSock) |
| 2263 |
|
ret = WSAStartup(MAKEWORD(2,2), &wsaData); |
| 2264 |
|
if (ret == 0) { |
| 2265 |
|
if (gethostname(host, sizeof(host)) != 0) { |
| 2266 |
|
ret = WSAGetLastError(); |
| 2267 |
|
} |
| 2268 |
|
WSACleanup(); |
| 2269 |
|
} |
| 2270 |
|
if (ret != 0) { |
| 2271 |
|
strcpy(host, "sai"); |
| 2272 |
|
} |
| 2273 |
|
|
| 2274 |
|
_snprintf(comment, maxlen, "%s@%s", user, host); |
| 2275 |
|
} |
| 2276 |
|
|
| 2277 |
|
// uuencode (rfc1521) |
| 2278 |
|
static int uuencode(unsigned char *src, int srclen, unsigned char *target, int targsize) |
| 2279 |
|
{ |
| 2280 |
|
char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 2281 |
|
char pad = '='; |
| 2282 |
|
int datalength = 0; |
| 2283 |
|
unsigned char input[3]; |
| 2284 |
|
unsigned char output[4]; |
| 2285 |
|
int i; |
| 2286 |
|
|
| 2287 |
|
while (srclen > 2) { |
| 2288 |
|
input[0] = *src++; |
| 2289 |
|
input[1] = *src++; |
| 2290 |
|
input[2] = *src++; |
| 2291 |
|
srclen -= 3; |
| 2292 |
|
|
| 2293 |
|
output[0] = input[0] >> 2; |
| 2294 |
|
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); |
| 2295 |
|
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); |
| 2296 |
|
output[3] = input[2] & 0x3f; |
| 2297 |
|
if (output[0] >= 64 || |
| 2298 |
|
output[1] >= 64 || |
| 2299 |
|
output[2] >= 64 || |
| 2300 |
|
output[3] >= 64) |
| 2301 |
|
return -1; |
| 2302 |
|
|
| 2303 |
|
if (datalength + 4 > targsize) |
| 2304 |
|
return (-1); |
| 2305 |
|
target[datalength++] = base64[output[0]]; |
| 2306 |
|
target[datalength++] = base64[output[1]]; |
| 2307 |
|
target[datalength++] = base64[output[2]]; |
| 2308 |
|
target[datalength++] = base64[output[3]]; |
| 2309 |
|
} |
| 2310 |
|
|
| 2311 |
|
if (srclen != 0) { |
| 2312 |
|
/* Get what's left. */ |
| 2313 |
|
input[0] = input[1] = input[2] = '\0'; |
| 2314 |
|
for (i = 0; i < srclen; i++) |
| 2315 |
|
input[i] = *src++; |
| 2316 |
|
|
| 2317 |
|
output[0] = input[0] >> 2; |
| 2318 |
|
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); |
| 2319 |
|
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); |
| 2320 |
|
if (output[0] >= 64 || |
| 2321 |
|
output[1] >= 64 || |
| 2322 |
|
output[2] >= 64) |
| 2323 |
|
return -1; |
| 2324 |
|
|
| 2325 |
|
if (datalength + 4 > targsize) |
| 2326 |
|
return (-1); |
| 2327 |
|
target[datalength++] = base64[output[0]]; |
| 2328 |
|
target[datalength++] = base64[output[1]]; |
| 2329 |
|
if (srclen == 1) |
| 2330 |
|
target[datalength++] = pad; |
| 2331 |
|
else |
| 2332 |
|
target[datalength++] = base64[output[2]]; |
| 2333 |
|
target[datalength++] = pad; |
| 2334 |
|
} |
| 2335 |
|
if (datalength >= targsize) |
| 2336 |
|
return (-1); |
| 2337 |
|
target[datalength] = '\0'; /* Returned value doesn't count \0. */ |
| 2338 |
|
|
| 2339 |
|
return (datalength); // success |
| 2340 |
|
} |
| 2341 |
|
|
| 2342 |
|
static BOOL CALLBACK TTXKeyGenerator(HWND dlg, UINT msg, WPARAM wParam, |
| 2343 |
|
LPARAM lParam) |
| 2344 |
|
{ |
| 2345 |
|
static enum hostkey_type key_type; |
| 2346 |
|
|
| 2347 |
|
switch (msg) { |
| 2348 |
|
case WM_INITDIALOG: |
| 2349 |
|
{ |
| 2350 |
|
// default key type |
| 2351 |
|
SendMessage(GetDlgItem(dlg, IDC_RSA_TYPE), BM_SETCHECK, BST_CHECKED, 0); |
| 2352 |
|
key_type = KEY_RSA; |
| 2353 |
|
|
| 2354 |
|
// passphrase edit box disabled(default) |
| 2355 |
|
EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE); |
| 2356 |
|
EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE); |
| 2357 |
|
|
| 2358 |
|
// file saving dialog disabled(default) |
| 2359 |
|
EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE); |
| 2360 |
|
EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE); |
| 2361 |
|
|
| 2362 |
|
} |
| 2363 |
|
return TRUE; |
| 2364 |
|
|
| 2365 |
|
case WM_COMMAND: |
| 2366 |
|
switch (LOWORD(wParam)) { |
| 2367 |
|
case IDOK: // key generate button pressed |
| 2368 |
|
// passphrase edit box disabled(default) |
| 2369 |
|
EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE); |
| 2370 |
|
EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE); |
| 2371 |
|
|
| 2372 |
|
// file saving dialog disabled(default) |
| 2373 |
|
EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE); |
| 2374 |
|
EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE); |
| 2375 |
|
|
| 2376 |
|
if (generate_ssh_key(key_type)) { |
| 2377 |
|
// passphrase edit box disabled(default) |
| 2378 |
|
EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), TRUE); |
| 2379 |
|
EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), TRUE); |
| 2380 |
|
|
| 2381 |
|
// file saving dialog disabled(default) |
| 2382 |
|
EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), TRUE); |
| 2383 |
|
EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), TRUE); |
| 2384 |
|
} |
| 2385 |
|
return TRUE; |
| 2386 |
|
|
| 2387 |
|
case IDCANCEL: |
| 2388 |
|
// don't forget to free SSH resource! |
| 2389 |
|
free_ssh_key(); |
| 2390 |
|
EndDialog(dlg, 0); // dialog close |
| 2391 |
|
return TRUE; |
| 2392 |
|
|
| 2393 |
|
// if radio button pressed... |
| 2394 |
|
case IDC_RSA1_TYPE | (BN_CLICKED << 16): |
| 2395 |
|
key_type = KEY_RSA1; |
| 2396 |
|
break; |
| 2397 |
|
|
| 2398 |
|
case IDC_RSA_TYPE | (BN_CLICKED << 16): |
| 2399 |
|
key_type = KEY_RSA; |
| 2400 |
|
break; |
| 2401 |
|
|
| 2402 |
|
case IDC_DSA_TYPE | (BN_CLICKED << 16): |
| 2403 |
|
key_type = KEY_DSA; |
| 2404 |
|
break; |
| 2405 |
|
|
| 2406 |
|
// saving public key file |
| 2407 |
|
case IDC_SAVE_PUBLIC_KEY: |
| 2408 |
|
{ |
| 2409 |
|
int ret; |
| 2410 |
|
OPENFILENAME ofn; |
| 2411 |
|
char filename[MAX_PATH]; |
| 2412 |
|
FILE *fp; |
| 2413 |
|
char comment[1024]; // comment string in private key |
| 2414 |
|
|
| 2415 |
|
arc4random_stir(); |
| 2416 |
|
|
| 2417 |
|
// saving file dialog |
| 2418 |
|
ZeroMemory(&ofn, sizeof(ofn)); |
| 2419 |
|
ofn.lStructSize = sizeof(ofn); |
| 2420 |
|
ofn.hwndOwner = dlg; |
| 2421 |
|
if (key_type == KEY_RSA1) { |
| 2422 |
|
ofn.lpstrFilter = "SSH1 RSA key(identity.pub)\0identity.pub\0All Files(*.*)\0*.*\0\0"; |
| 2423 |
|
_snprintf(filename, sizeof(filename), "identity.pub"); |
| 2424 |
|
} else if (key_type == KEY_RSA) { |
| 2425 |
|
ofn.lpstrFilter = "SSH2 RSA key(id_rsa.pub)\0id_rsa.pub\0All Files(*.*)\0*.*\0\0"; |
| 2426 |
|
_snprintf(filename, sizeof(filename), "id_rsa.pub"); |
| 2427 |
|
} else { |
| 2428 |
|
ofn.lpstrFilter = "SSH2 DSA key(id_dsa.pub)\0id_dsa.pub\0All Files(*.*)\0*.*\0\0"; |
| 2429 |
|
_snprintf(filename, sizeof(filename), "id_dsa.pub"); |
| 2430 |
|
} |
| 2431 |
|
ofn.lpstrFile = filename; |
| 2432 |
|
ofn.nMaxFile = sizeof(filename); |
| 2433 |
|
ofn.lpstrTitle = "Save public key as:"; |
| 2434 |
|
if (GetSaveFileName(&ofn) == 0) { // failure |
| 2435 |
|
ret = CommDlgExtendedError(); |
| 2436 |
|
break; |
| 2437 |
|
} |
| 2438 |
|
|
| 2439 |
|
ssh_make_comment(comment, sizeof(comment)); |
| 2440 |
|
|
| 2441 |
|
// saving public key file |
| 2442 |
|
fp = fopen(filename, "wb"); |
| 2443 |
|
if (fp == NULL) { |
| 2444 |
|
MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION); |
| 2445 |
|
break; |
| 2446 |
|
} |
| 2447 |
|
|
| 2448 |
|
if (key_type == KEY_RSA1) { // SSH1 RSA |
| 2449 |
|
RSA *rsa = public_key.rsa; |
| 2450 |
|
int bits; |
| 2451 |
|
char *buf; |
| 2452 |
|
|
| 2453 |
|
bits = BN_num_bits(rsa->n); |
| 2454 |
|
fprintf(fp, "%u", bits); |
| 2455 |
|
|
| 2456 |
|
buf = BN_bn2dec(rsa->e); |
| 2457 |
|
fprintf(fp, " %s", buf); |
| 2458 |
|
OPENSSL_free(buf); |
| 2459 |
|
|
| 2460 |
|
buf = BN_bn2dec(rsa->n); |
| 2461 |
|
fprintf(fp, " %s", buf); |
| 2462 |
|
OPENSSL_free(buf); |
| 2463 |
|
|
| 2464 |
|
} else { // SSH2 RSA, DSA |
| 2465 |
|
buffer_t *b; |
| 2466 |
|
char *keyname; |
| 2467 |
|
DSA *dsa = public_key.dsa; |
| 2468 |
|
RSA *rsa = public_key.rsa; |
| 2469 |
|
int len; |
| 2470 |
|
char *blob; |
| 2471 |
|
char *uuenc; // uuencode data |
| 2472 |
|
int uulen; |
| 2473 |
|
|
| 2474 |
|
b = buffer_init(); |
| 2475 |
|
if (b == NULL) |
| 2476 |
|
goto public_error; |
| 2477 |
|
|
| 2478 |
|
if (key_type == KEY_DSA) { // DSA |
| 2479 |
|
keyname = "ssh-dss"; |
| 2480 |
|
buffer_put_string(b, keyname, strlen(keyname)); |
| 2481 |
|
buffer_put_bignum2(b, dsa->p); |
| 2482 |
|
buffer_put_bignum2(b, dsa->q); |
| 2483 |
|
buffer_put_bignum2(b, dsa->g); |
| 2484 |
|
buffer_put_bignum2(b, dsa->pub_key); |
| 2485 |
|
|
| 2486 |
|
} else { // RSA |
| 2487 |
|
keyname = "ssh-rsa"; |
| 2488 |
|
buffer_put_string(b, keyname, strlen(keyname)); |
| 2489 |
|
buffer_put_bignum2(b, rsa->e); |
| 2490 |
|
buffer_put_bignum2(b, rsa->n); |
| 2491 |
|
} |
| 2492 |
|
|
| 2493 |
|
blob = buffer_ptr(b); |
| 2494 |
|
len = buffer_len(b); |
| 2495 |
|
uuenc = malloc(len * 2); |
| 2496 |
|
if (uuenc == NULL) { |
| 2497 |
|
buffer_free(b); |
| 2498 |
|
goto public_error; |
| 2499 |
|
} |
| 2500 |
|
uulen = uuencode(blob, len, uuenc, len * 2); |
| 2501 |
|
if (uulen > 0) { |
| 2502 |
|
fprintf(fp, "%s %s", keyname, uuenc); |
| 2503 |
|
} |
| 2504 |
|
free(uuenc); |
| 2505 |
|
buffer_free(b); |
| 2506 |
|
} |
| 2507 |
|
|
| 2508 |
|
// writing a comment(+LF) |
| 2509 |
|
fprintf(fp, " %s", comment); |
| 2510 |
|
fputc(0x0a, fp); |
| 2511 |
|
|
| 2512 |
|
public_error: |
| 2513 |
|
fclose(fp); |
| 2514 |
|
|
| 2515 |
|
} |
| 2516 |
|
break; |
| 2517 |
|
|
| 2518 |
|
// saving private key file |
| 2519 |
|
case IDC_SAVE_PRIVATE_KEY: |
| 2520 |
|
{ |
| 2521 |
|
char buf[1024], buf_conf[1024]; // passphrase |
| 2522 |
|
int ret; |
| 2523 |
|
OPENFILENAME ofn; |
| 2524 |
|
char filename[MAX_PATH]; |
| 2525 |
|
char comment[1024]; // comment string in private key |
| 2526 |
|
|
| 2527 |
|
// パスフレーズのチェックを行う。パスフレーズは秘密鍵ファイルに付ける。 |
| 2528 |
|
SendMessage(GetDlgItem(dlg, IDC_KEY_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf); |
| 2529 |
|
SendMessage(GetDlgItem(dlg, IDC_CONFIRM_EDIT), WM_GETTEXT, sizeof(buf_conf), (LPARAM)buf_conf); |
| 2530 |
|
|
| 2531 |
|
// check matching |
| 2532 |
|
if (strcmp(buf, buf_conf) != 0) { |
| 2533 |
|
MessageBox(dlg, "Two passphrases don't match.", "ERROR", MB_OK | MB_ICONEXCLAMATION); |
| 2534 |
|
break; |
| 2535 |
|
} |
| 2536 |
|
|
| 2537 |
|
// check empty-passphrase (this is warning level) |
| 2538 |
|
if (buf[0] == '\0') { |
| 2539 |
|
ret = MessageBox(dlg, "Are you sure that you want to use a empty passphrase?", "WARNING", MB_YESNO | MB_ICONWARNING); |
| 2540 |
|
if (ret == IDNO) |
| 2541 |
|
break; |
| 2542 |
|
} |
| 2543 |
|
|
| 2544 |
|
ssh_make_comment(comment, sizeof(comment)); |
| 2545 |
|
|
| 2546 |
|
// saving file dialog |
| 2547 |
|
ZeroMemory(&ofn, sizeof(ofn)); |
| 2548 |
|
ofn.lStructSize = sizeof(ofn); |
| 2549 |
|
ofn.hwndOwner = dlg; |
| 2550 |
|
if (key_type == KEY_RSA1) { |
| 2551 |
|
ofn.lpstrFilter = "SSH1 RSA key(identity)\0identity\0All Files(*.*)\0*.*\0\0"; |
| 2552 |
|
_snprintf(filename, sizeof(filename), "identity"); |
| 2553 |
|
} else if (key_type == KEY_RSA) { |
| 2554 |
|
ofn.lpstrFilter = "SSH2 RSA key(id_rsa)\0id_rsa\0All Files(*.*)\0*.*\0\0"; |
| 2555 |
|
_snprintf(filename, sizeof(filename), "id_rsa"); |
| 2556 |
|
} else { |
| 2557 |
|
ofn.lpstrFilter = "SSH2 DSA key(id_dsa)\0id_dsa\0All Files(*.*)\0*.*\0\0"; |
| 2558 |
|
_snprintf(filename, sizeof(filename), "id_dsa"); |
| 2559 |
|
} |
| 2560 |
|
ofn.lpstrFile = filename; |
| 2561 |
|
ofn.nMaxFile = sizeof(filename); |
| 2562 |
|
ofn.lpstrTitle = "Save private key as:"; |
| 2563 |
|
if (GetSaveFileName(&ofn) == 0) { // failure |
| 2564 |
|
ret = CommDlgExtendedError(); |
| 2565 |
|
break; |
| 2566 |
|
} |
| 2567 |
|
|
| 2568 |
|
// saving private key file |
| 2569 |
|
if (key_type == KEY_RSA1) { // SSH1 RSA |
| 2570 |
|
int cipher_num; |
| 2571 |
|
buffer_t *b, *enc; |
| 2572 |
|
unsigned int rnd; |
| 2573 |
|
unsigned char tmp[128]; |
| 2574 |
|
RSA *rsa; |
| 2575 |
|
int i, len; |
| 2576 |
|
char authfile_id_string[] = "SSH PRIVATE KEY FILE FORMAT 1.1"; |
| 2577 |
|
MD5_CTX md; |
| 2578 |
|
unsigned char digest[16]; |
| 2579 |
|
char *passphrase = buf; |
| 2580 |
|
EVP_CIPHER_CTX cipher_ctx; |
| 2581 |
|
FILE *fp; |
| 2582 |
|
char wrapped[4096]; |
| 2583 |
|
|
| 2584 |
|
if (passphrase[0] == '\0') { // passphrase is empty |
| 2585 |
|
cipher_num = SSH_CIPHER_NONE; |
| 2586 |
|
} else { |
| 2587 |
|
cipher_num = SSH_CIPHER_3DES; // 3DES-CBC |
| 2588 |
|
} |
| 2589 |
|
|
| 2590 |
|
b = buffer_init(); |
| 2591 |
|
if (b == NULL) |
| 2592 |
|
break; |
| 2593 |
|
enc = buffer_init(); |
| 2594 |
|
if (enc == NULL) { |
| 2595 |
|
buffer_free(b); |
| 2596 |
|
break; |
| 2597 |
|
} |
| 2598 |
|
|
| 2599 |
|
// set random value |
| 2600 |
|
rnd = arc4random(); |
| 2601 |
|
tmp[0] = rnd & 0xff; |
| 2602 |
|
tmp[1] = (rnd >> 8) & 0xff; |
| 2603 |
|
tmp[2] = tmp[0]; |
| 2604 |
|
tmp[3] = tmp[1]; |
| 2605 |
|
buffer_append(b, tmp, 4); |
| 2606 |
|
|
| 2607 |
|
// set private key |
| 2608 |
|
rsa = private_key.rsa; |
| 2609 |
|
buffer_put_bignum(b, rsa->d); |
| 2610 |
|
buffer_put_bignum(b, rsa->iqmp); |
| 2611 |
|
buffer_put_bignum(b, rsa->q); |
| 2612 |
|
buffer_put_bignum(b, rsa->p); |
| 2613 |
|
|
| 2614 |
|
// padding with 8byte align |
| 2615 |
|
while (buffer_len(b) % 8) { |
| 2616 |
|
buffer_put_char(b, 0); |
| 2617 |
|
} |
| 2618 |
|
|
| 2619 |
|
// |
| 2620 |
|
// step(2) |
| 2621 |
|
// |
| 2622 |
|
// encrypted buffer |
| 2623 |
|
/* First store keyfile id string. */ |
| 2624 |
|
for (i = 0 ; authfile_id_string[i] ; i++) { |
| 2625 |
|
buffer_put_char(enc, authfile_id_string[i]); |
| 2626 |
|
} |
| 2627 |
|
buffer_put_char(enc, 0x0a); // LF |
| 2628 |
|
buffer_put_char(enc, 0); |
| 2629 |
|
|
| 2630 |
|
/* Store cipher type. */ |
| 2631 |
|
buffer_put_char(enc, cipher_num); |
| 2632 |
|
buffer_put_int(enc, 0); // type is 'int'!! (For future extension) |
| 2633 |
|
|
| 2634 |
|
/* Store public key. This will be in plain text. */ |
| 2635 |
|
buffer_put_int(enc, BN_num_bits(rsa->n)); |
| 2636 |
|
buffer_put_bignum(enc, rsa->n); |
| 2637 |
|
buffer_put_bignum(enc, rsa->e); |
| 2638 |
|
buffer_put_string(enc, comment, strlen(comment)); |
| 2639 |
|
|
| 2640 |
|
// setup the MD5ed passphrase to cipher encryption key |
| 2641 |
|
MD5_Init(&md); |
| 2642 |
|
MD5_Update(&md, (const unsigned char *)passphrase, strlen(passphrase)); |
| 2643 |
|
MD5_Final(digest, &md); |
| 2644 |
|
if (cipher_num == SSH_CIPHER_NONE) { |
| 2645 |
|
cipher_init_SSH2(&cipher_ctx, digest, 16, NULL, 0, CIPHER_ENCRYPT, EVP_enc_null); |
| 2646 |
|
} else { |
| 2647 |
|
cipher_init_SSH2(&cipher_ctx, digest, 16, NULL, 0, CIPHER_ENCRYPT, evp_ssh1_3des); |
| 2648 |
|
} |
| 2649 |
|
len = buffer_len(b); |
| 2650 |
|
if (len % 8) { // fatal error |
| 2651 |
|
goto error; |
| 2652 |
|
} |
| 2653 |
|
|
| 2654 |
|
// check buffer overflow |
| 2655 |
|
if (buffer_overflow_verify(enc, len) && (sizeof(wrapped) < len)) { |
| 2656 |
|
goto error; |
| 2657 |
|
} |
| 2658 |
|
|
| 2659 |
|
if (EVP_Cipher(&cipher_ctx, wrapped, buffer_ptr(b), len) == 0) { |
| 2660 |
|
goto error; |
| 2661 |
|
} |
| 2662 |
|
if (EVP_CIPHER_CTX_cleanup(&cipher_ctx) == 0) { |
| 2663 |
|
goto error; |
| 2664 |
|
} |
| 2665 |
|
|
| 2666 |
|
buffer_append(enc, wrapped, len); |
| 2667 |
|
|
| 2668 |
|
// saving private key file (binary mode) |
| 2669 |
|
fp = fopen(filename, "wb"); |
| 2670 |
|
if (fp == NULL) { |
| 2671 |
|
MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION); |
| 2672 |
|
break; |
| 2673 |
|
} |
| 2674 |
|
fwrite(buffer_ptr(enc), buffer_len(enc), 1, fp); |
| 2675 |
|
|
| 2676 |
|
fclose(fp); |
| 2677 |
|
|
| 2678 |
|
error:; |
| 2679 |
|
buffer_free(b); |
| 2680 |
|
buffer_free(enc); |
| 2681 |
|
|
| 2682 |
|
} else { // SSH2 RSA, DSA |
| 2683 |
|
int len; |
| 2684 |
|
FILE *fp; |
| 2685 |
|
const EVP_CIPHER *cipher; |
| 2686 |
|
|
| 2687 |
|
len = strlen(buf); |
| 2688 |
|
// TODO: range check (len >= 4) |
| 2689 |
|
|
| 2690 |
|
cipher = NULL; |
| 2691 |
|
if (len > 0) { |
| 2692 |
|
cipher = EVP_des_ede3_cbc(); |
| 2693 |
|
} |
| 2694 |
|
|
| 2695 |
|
fp = fopen(filename, "w"); |
| 2696 |
|
if (fp == NULL) { |
| 2697 |
|
MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION); |
| 2698 |
|
break; |
| 2699 |
|
} |
| 2700 |
|
|
| 2701 |
|
if (key_type == KEY_RSA) { // RSA |
| 2702 |
|
ret = PEM_write_RSAPrivateKey(fp, private_key.rsa, cipher, buf, len, NULL, NULL); |
| 2703 |
|
} else { // DSA |
| 2704 |
|
ret = PEM_write_DSAPrivateKey(fp, private_key.dsa, cipher, buf, len, NULL, NULL); |
| 2705 |
|
} |
| 2706 |
|
if (ret == 0) { |
| 2707 |
|
MessageBox(dlg, "Can't write key file", "ERROR", MB_OK | MB_ICONEXCLAMATION); |
| 2708 |
|
} |
| 2709 |
|
fclose(fp); |
| 2710 |
|
} |
| 2711 |
|
|
| 2712 |
|
|
| 2713 |
|
} |
| 2714 |
|
break; |
| 2715 |
|
|
| 2716 |
|
} |
| 2717 |
|
break; |
| 2718 |
|
} |
| 2719 |
|
|
| 2720 |
|
return FALSE; |
| 2721 |
|
} |
| 2722 |
|
|
| 2723 |
|
|
| 2724 |
static int PASCAL FAR TTXProcessCommand(HWND hWin, WORD cmd) |
static int PASCAL FAR TTXProcessCommand(HWND hWin, WORD cmd) |
| 2725 |
{ |
{ |
| 2726 |
GET_VAR(); |
GET_VAR(); |
| 2730 |
} |
} |
| 2731 |
|
|
| 2732 |
switch (cmd) { |
switch (cmd) { |
| 2733 |
|
case ID_SSHKEYGENMENU: |
| 2734 |
|
if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHKEYGEN), hWin, TTXKeyGenerator, |
| 2735 |
|
(LPARAM) pvar) == -1) { |
| 2736 |
|
MessageBox(hWin, "Cannot create Key Generator window.", |
| 2737 |
|
"TTSSH Error", MB_OK | MB_ICONEXCLAMATION); |
| 2738 |
|
} |
| 2739 |
|
return 1; |
| 2740 |
|
|
| 2741 |
case ID_ABOUTMENU: |
case ID_ABOUTMENU: |
| 2742 |
if (DialogBoxParam |
if (DialogBoxParam |
| 2743 |
(hInst, MAKEINTRESOURCE(IDD_ABOUTDIALOG), hWin, TTXAboutDlg, |
(hInst, MAKEINTRESOURCE(IDD_ABOUTDIALOG), hWin, TTXAboutDlg, |
| 3063 |
|
|
| 3064 |
/* |
/* |
| 3065 |
* $Log: not supported by cvs2svn $ |
* $Log: not supported by cvs2svn $ |
| 3066 |
|
* Revision 1.19 2005/04/08 14:55:03 yutakakn |
| 3067 |
|
* "Duplicate session"においてSSH自動ログインを行うようにした。 |
| 3068 |
|
* |
| 3069 |
* Revision 1.18 2005/04/03 14:39:48 yutakakn |
* Revision 1.18 2005/04/03 14:39:48 yutakakn |
| 3070 |
* SSH2 channel lookup機構の追加(ポートフォワーディングのため)。 |
* SSH2 channel lookup機構の追加(ポートフォワーディングのため)。 |
| 3071 |
* TTSSH 2.10で追加したlog dump機構において、DH鍵再作成時にbuffer freeで |
* TTSSH 2.10で追加したlog dump機構において、DH鍵再作成時にbuffer freeで |