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