• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the License); you may
5  *  not use this file except in compliance with the License.
6  *
7  *  http://www.apache.org/licenses/LICENSE-2.0
8  */
9 
10 
11 #include <stdio.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <gmssl/mem.h>
16 #include <gmssl/sm4.h>
17 #include <gmssl/hex.h>
18 
19 
20 #define SM4_MODE_CBC 1
21 #define SM4_MODE_CTR 2
22 
23 static const char *options = "{-cbc|-ctr} {-encrypt|-decrypt} -key hex -iv hex [-in file] [-out file]";
24 
sm4_main(int argc,char ** argv)25 int sm4_main(int argc, char **argv)
26 {
27 	int ret = 1;
28 	char *prog = argv[0];
29 	char *keyhex = NULL;
30 	char *ivhex = NULL;
31 	char *infile = NULL;
32 	char *outfile = NULL;
33 	uint8_t key[16];
34 	uint8_t iv[16];
35 	size_t keylen = sizeof(key);
36 	size_t ivlen = sizeof(iv);
37 	FILE *infp = stdin;
38 	FILE *outfp = stdout;
39 	int mode = 0;
40 	int enc = -1;
41 	SM4_CBC_CTX cbc_ctx;
42 	SM4_CTR_CTX ctr_ctx;
43 	uint8_t inbuf[4096];
44 	size_t inlen;
45 	uint8_t outbuf[4196];
46 	size_t outlen;
47 
48 	argc--;
49 	argv++;
50 
51 	if (argc < 1) {
52 		fprintf(stderr, "usage: %s %s\n", prog, options);
53 		return 1;
54 	}
55 
56 	while (argc > 0) {
57 		if (!strcmp(*argv, "-help")) {
58 			printf("usage: %s %s\n", prog, options);
59 			ret = 0;
60 			goto end;
61 		} else if (!strcmp(*argv, "-key")) {
62 			if (--argc < 1) goto bad;
63 			keyhex = *(++argv);
64 			if (strlen(keyhex) != sizeof(key) * 2) {
65 				fprintf(stderr, "%s: invalid key length\n", prog);
66 				goto end;
67 			}
68 			if (hex_to_bytes(keyhex, strlen(keyhex), key, &keylen) != 1) {
69 				fprintf(stderr, "%s: invalid HEX digits\n", prog);
70 				goto end;
71 			}
72 		} else if (!strcmp(*argv, "-iv")) {
73 			if (--argc < 1) goto bad;
74 			ivhex = *(++argv);
75 			if (strlen(ivhex) != sizeof(iv) * 2) {
76 				fprintf(stderr, "%s: invalid IV length\n", prog);
77 				goto end;
78 			}
79 			if (hex_to_bytes(ivhex, strlen(ivhex), iv, &ivlen) != 1) {
80 				fprintf(stderr, "%s: invalid HEX digits\n", prog);
81 				goto end;
82 			}
83 		} else if (!strcmp(*argv, "-encrypt")) {
84 			enc = 1;
85 		} else if (!strcmp(*argv, "-decrypt")) {
86 			enc = 0;
87 		} else if (!strcmp(*argv, "-cbc")) {
88 			if (mode) goto bad;
89 			mode = SM4_MODE_CBC;
90 		} else if (!strcmp(*argv, "-ctr")) {
91 			if (mode) goto bad;
92 			mode = SM4_MODE_CTR;
93 		} else if (!strcmp(*argv, "-in")) {
94 			if (--argc < 1) goto bad;
95 			infile = *(++argv);
96 			if (!(infp = fopen(infile, "r"))) {
97 				fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno));
98 				goto end;
99 			}
100 		} else if (!strcmp(*argv, "-out")) {
101 			if (--argc < 1) goto bad;
102 			outfile = *(++argv);
103 			if (!(outfp = fopen(outfile, "w"))) {
104 				fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
105 				goto end;
106 			}
107 		} else {
108 			fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
109 			goto end;
110 bad:
111 			fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv);
112 			goto end;
113 		}
114 
115 		argc--;
116 		argv++;
117 	}
118 
119 	if (!mode) {
120 		fprintf(stderr, "%s: mode not assigned, -cbc or -ctr option required\n", prog);
121 		goto end;
122 	}
123 	if (!keyhex) {
124 		fprintf(stderr, "%s: option '-key' missing\n", prog);
125 		goto end;
126 	}
127 	if (!ivhex) {
128 		fprintf(stderr, "%s: option '-iv' missing\n", prog);
129 		goto end;
130 	}
131 
132 
133 	if (mode == SM4_MODE_CTR) {
134 		if (sm4_ctr_encrypt_init(&ctr_ctx, key, iv) != 1) {
135 			fprintf(stderr, "%s: inner error\n", prog);
136 			goto end;
137 		}
138 		while ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) > 0) {
139 			if (sm4_ctr_encrypt_update(&ctr_ctx, inbuf, inlen, outbuf, &outlen) != 1) {
140 				fprintf(stderr, "%s: inner error\n", prog);
141 				goto end;
142 			}
143 			if (fwrite(outbuf, 1, outlen, outfp) != outlen) {
144 				fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
145 				goto end;
146 			}
147 		}
148 		if (sm4_ctr_encrypt_finish(&ctr_ctx, outbuf, &outlen) != 1) {
149 			fprintf(stderr, "%s: inner error\n", prog);
150 			goto end;
151 		}
152 		if (fwrite(outbuf, 1, outlen, outfp) != outlen) {
153 			fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
154 			goto end;
155 		}
156 
157 		ret = 0;
158 		goto end;
159 	}
160 
161 	if (enc < 0) {
162 		fprintf(stderr, "%s: option -encrypt or -decrypt should be set\n", prog);
163 		goto end;
164 	}
165 
166 	if (enc) {
167 		if (sm4_cbc_encrypt_init(&cbc_ctx, key, iv) != 1) {
168 			fprintf(stderr, "%s: inner error\n", prog);
169 			goto end;
170 		}
171 		while ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) > 0) {
172 			if (sm4_cbc_encrypt_update(&cbc_ctx, inbuf, inlen, outbuf, &outlen) != 1) {
173 				fprintf(stderr, "%s: inner error\n", prog);
174 				goto end;
175 			}
176 			if (fwrite(outbuf, 1, outlen, outfp) != outlen) {
177 				fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
178 				goto end;
179 			}
180 		}
181 		if (sm4_cbc_encrypt_finish(&cbc_ctx, outbuf, &outlen) != 1) {
182 			fprintf(stderr, "%s: inner error\n", prog);
183 			goto end;
184 		}
185 		if (fwrite(outbuf, 1, outlen, outfp) != outlen) {
186 			fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
187 			goto end;
188 		}
189 
190 	} else {
191 		if (sm4_cbc_decrypt_init(&cbc_ctx, key, iv) != 1) {
192 			fprintf(stderr, "%s: inner error\n", prog);
193 			goto end;
194 		}
195 		while ((inlen = fread(inbuf, 1, sizeof(inbuf), infp)) > 0) {
196 			if (sm4_cbc_decrypt_update(&cbc_ctx, inbuf, inlen, outbuf, &outlen) != 1) {
197 				fprintf(stderr, "%s: inner error\n", prog);
198 				goto end;
199 			}
200 			if (fwrite(outbuf, 1, outlen, outfp) != outlen) {
201 				fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
202 				goto end;
203 			}
204 		}
205 		if (sm4_cbc_decrypt_finish(&cbc_ctx, outbuf, &outlen) != 1) {
206 			fprintf(stderr, "%s: inner error\n", prog);
207 			goto end;
208 		}
209 		if (fwrite(outbuf, 1, outlen, outfp) != outlen) {
210 			fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
211 			goto end;
212 		}
213 	}
214 	ret = 0;
215 
216 end:
217 	gmssl_secure_clear(&cbc_ctx, sizeof(cbc_ctx));
218 	gmssl_secure_clear(&ctr_ctx, sizeof(ctr_ctx));
219 	gmssl_secure_clear(key, sizeof(key));
220 	gmssl_secure_clear(iv, sizeof(iv));
221 	gmssl_secure_clear(inbuf, sizeof(inbuf));
222 	gmssl_secure_clear(outbuf, sizeof(outbuf));
223 	if (infile && infp) fclose(infp);
224 	if (outfile && outfp) fclose(outfp);
225 	return ret;
226 }
227