1c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh/* $NetBSD: plainrsa-gen.c,v 1.4 2006/09/09 16:22:10 manu Exp $ */ 20a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 30a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* Id: plainrsa-gen.c,v 1.6 2005/04/21 09:08:40 monas Exp */ 40a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* 50a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Copyright (C) 2004 SuSE Linux AG, Nuernberg, Germany. 60a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Contributed by: Michal Ludvig <mludvig@suse.cz>, SUSE Labs 70a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * All rights reserved. 80a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 90a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * Redistribution and use in source and binary forms, with or without 100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * modification, are permitted provided that the following conditions 110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * are met: 120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 1. Redistributions of source code must retain the above copyright 130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * notice, this list of conditions and the following disclaimer. 140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 2. Redistributions in binary form must reproduce the above copyright 150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * notice, this list of conditions and the following disclaimer in the 160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * documentation and/or other materials provided with the distribution. 170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 3. Neither the name of the project nor the names of its contributors 180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * may be used to endorse or promote products derived from this software 190a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * without specific prior written permission. 200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * 210a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 240a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 250a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 260a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 270a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 280a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 290a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * SUCH DAMAGE. 320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */ 330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* This file contains a generator for FreeS/WAN-style ipsec.secrets RSA keys. */ 350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "config.h" 370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 380a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <stdio.h> 390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <string.h> 400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <errno.h> 410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/types.h> 430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/stat.h> 440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <sys/socket.h> 450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <unistd.h> 460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/bio.h> 480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/bn.h> 490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/err.h> 500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/objects.h> 510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/rsa.h> 520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/evp.h> 530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#ifdef HAVE_OPENSSL_ENGINE_H 540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include <openssl/engine.h> 550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#endif 560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "misc.h" 580a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "vmbuf.h" 590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "plog.h" 600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "crypto_openssl.h" 610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang#include "package_version.h" 630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 640a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangvoid 650a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangusage (char *argv0) 660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 670a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "Plain RSA key generator, part of %s\n", TOP_PACKAGE_STRING); 680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "By Michal Ludvig (http://www.logix.cz/michal)\n"); 690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "\n"); 700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "Usage: %s [options]\n", argv0); 710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "\n"); 720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, " -b bits Generate <bits> long RSA key (default=1024)\n"); 730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, " -e pubexp Public exponent to use (default=0x3)\n"); 740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, " -f filename Filename to store the key to (default=stdout)\n"); 750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, " -h Help\n"); 760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "\n"); 770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "Report bugs to <ipsec-tools-devel@lists.sourceforge.net>\n"); 780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang exit(1); 790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang/* 820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang * See RFC 2065, section 3.5 for details about the output format. 830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang */ 840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangvchar_t * 85c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehmix_b64_pubkey(RSA *key) 860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 870a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang char *binbuf; 880a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang long binlen, ret; 890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang vchar_t *res; 900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang binlen = 1 + BN_num_bytes(key->e) + BN_num_bytes(key->n); 920a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang binbuf = malloc(binlen); 930a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang memset(binbuf, 0, binlen); 940a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang binbuf[0] = BN_bn2bin(key->e, (unsigned char *) &binbuf[1]); 950a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang ret = BN_bn2bin(key->n, (unsigned char *) (&binbuf[binbuf[0] + 1])); 960a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (1 + binbuf[0] + ret != binlen) { 970a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang plog(LLV_ERROR, LOCATION, NULL, 980a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang "Pubkey generation failed. This is really strange...\n"); 990a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return NULL; 1000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return base64_encode(binbuf, binlen); 1030a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangchar * 1060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wanglowercase(char *input) 1070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 1080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang char *ptr = input; 1090a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang while (*ptr) { 1100a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (*ptr >= 'A' && *ptr <= 'F') 1110a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *ptr -= 'A' - 'a'; 1120a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang *ptr++; 1130a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1140a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1150a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return input; 1160a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1170a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1180a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint 119c91307af2622f6625525f3c1f9c954376df950adChia-chi Yehgen_rsa_key(FILE *fp, size_t bits, unsigned long exp) 1200a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 121c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh RSA *key; 1220a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang vchar_t *pubkey64 = NULL; 1230a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 124c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh key = RSA_generate_key(bits, exp, NULL, NULL); 125c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh if (!key) { 126c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh fprintf(stderr, "RSA_generate_key(): %s\n", eay_strerror()); 127c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh return -1; 128c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh } 129c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh 1300a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang pubkey64 = mix_b64_pubkey(key); 1310a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (!pubkey64) { 1320a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(stderr, "mix_b64_pubkey(): %s\n", eay_strerror()); 1330a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return -1; 1340a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1350a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1360a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "# : PUB 0s%s\n", pubkey64->v); 1370a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, ": RSA\t{\n"); 138c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh fprintf(fp, "\t# RSA %zu bits\n", bits); 1390a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\t# pubkey=0s%s\n", pubkey64->v); 1400a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tModulus: 0x%s\n", lowercase(BN_bn2hex(key->n))); 1410a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tPublicExponent: 0x%s\n", lowercase(BN_bn2hex(key->e))); 1420a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tPrivateExponent: 0x%s\n", lowercase(BN_bn2hex(key->d))); 1430a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tPrime1: 0x%s\n", lowercase(BN_bn2hex(key->p))); 1440a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tPrime2: 0x%s\n", lowercase(BN_bn2hex(key->q))); 1450a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tExponent1: 0x%s\n", lowercase(BN_bn2hex(key->dmp1))); 1460a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tExponent2: 0x%s\n", lowercase(BN_bn2hex(key->dmq1))); 1470a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, "\tCoefficient: 0x%s\n", lowercase(BN_bn2hex(key->iqmp))); 1480a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fprintf(fp, " }\n"); 1490a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1500a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang vfree(pubkey64); 1510a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1520a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return 0; 1530a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 1540a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1550a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangint 1560a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wangmain (int argc, char *argv[]) 1570a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang{ 158c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh FILE *fp = stdout; 1590a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang size_t bits = 1024; 1600a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang unsigned int pubexp = 0x3; 1610a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang struct stat st; 1620a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang extern char *optarg; 1630a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang extern int optind; 164c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh int c; 165c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh char *fname = NULL; 1660a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 167c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh while ((c = getopt(argc, argv, "e:b:f:h")) != -1) 1680a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang switch (c) { 1690a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang case 'e': 1700a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (strncmp(optarg, "0x", 2) == 0) 1710a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang sscanf(optarg, "0x%x", &pubexp); 1720a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang else 1730a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang pubexp = atoi(optarg); 1740a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang break; 1750a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang case 'b': 1760a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang bits = atoi(optarg); 1770a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang break; 1780a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang case 'f': 1790a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fname = optarg; 1800a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang break; 1810a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang case 'h': 1820a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang default: 1830a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang usage(argv[0]); 1840a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1850a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 1860a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang if (fname) { 187c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh if (stat(fname, &st) >= 0) { 188c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh fprintf(stderr, "%s: file exists! Please use a different name.\n", fname); 1890a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang exit(1); 1900a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang } 1910a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 192c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh umask(0077); 193c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh fp = fopen(fname, "w"); 194c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh if (fp == NULL) { 195f8a6a7636d53a5730c58ae041e4e09ae12e1657cChia-chi Yeh fprintf(stderr, "%s: %s\n", fname, strerror(errno)); 196f8a6a7636d53a5730c58ae041e4e09ae12e1657cChia-chi Yeh exit(1); 197f8a6a7636d53a5730c58ae041e4e09ae12e1657cChia-chi Yeh } 198f8a6a7636d53a5730c58ae041e4e09ae12e1657cChia-chi Yeh } 199f8a6a7636d53a5730c58ae041e4e09ae12e1657cChia-chi Yeh 2000a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang ploginit(); 2010a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang eay_init(); 2020a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 203c91307af2622f6625525f3c1f9c954376df950adChia-chi Yeh gen_rsa_key(fp, bits, pubexp); 2040a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 2050a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang fclose(fp); 2060a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang 2070a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang return 0; 2080a1907d434839af6a9cb6329bbde60b237bf53dcChung-yih Wang} 209