root/WizardsToolkit/trunk/utilities/encipher.c

Revision 339, 35.4 KB (checked in by cristy, 6 weeks ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%            EEEEE  N   N   CCCC  IIIII  PPPP   H   H  EEEEE  RRRR            %
7%            E      NN  N  C        I    P   P  H   H  E      R   R           %
8%            EEE    N N N  C        I    PPPP   HHHHH  EEE    RRRR            %
9%            E      N  NN  C        I    P      H   H  E      R R             %
10%            EEEEE  N   N   CCCC  IIIII  P      H   H  EEEEE  R  R            %
11%                                                                             %
12%                                                                             %
13%                        Convert Plaintext To Ciphertext                      %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                January 2008                                 %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.wizards-toolkit.org/script/license.php                        %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <time.h>
46#include "wizard/studio.h"
47#include "wizard/WizardsToolkit.h"
48#include "wizard/blob-private.h"
49#include "wizard/exception-private.h"
50#if defined(WIZARDSTOOLKIT_HAVE_UTIME)
51#if defined(WIZARDSTOOLKIT_HAVE_UTIME_H)
52#include <utime.h>
53#else
54#include <sys/utime.h>
55#endif
56#endif
57#if defined(__WINDOWS__)
58#include <windows.h>
59#endif
60#include "content.h"
61#include "utility_.h"
62
63/*
64  Forward declaraction.
65*/
66static WizardBooleanType
67  EncipherContent(ContentInfo *,const char *,const char *,
68    const WizardBooleanType,ExceptionInfo *);
69
70/*
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72%                                                                             %
73%                                                                             %
74%                                                                             %
75+   E n c i p h e r C o m m a n d                                             %
76%                                                                             %
77%                                                                             %
78%                                                                             %
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%
81%  EncipherCommand() reads plaintext from a file and converts it to ciphertext.
82%
83%  The format of the EncipherCommand method is:
84%
85%      WizardBooleanType EncipherCommand(int argc,char **argv,
86%        ExceptionInfo *exception)
87%
88%  A description of each parameter follows:
89%
90%    o argc: The number of elements in the argument vector.
91%
92%    o argv: A text array containing the command line arguments.
93%
94%    o exception: Return any errors or warnings in this structure.
95%
96*/
97
98static void EncipherUsage()
99{
100  static const char
101    *options[]=
102    {
103      "-authenticate method authenticate with this method: Secret or Public",
104      "-chunksize bytes     number of bytes in a chunk",
105      "-cipher type         cipher to encipher content",
106      "-debug events        display copious debugging information",
107      "-(de)compress        automagically (de)compress BZIP and ZIP files",
108      "-entropy type        increase content entropy",
109      "-help                print program options",
110      "-hmac hash           ensure message integrity with this hash",
111      "-key hash            strengthen the key with this hash",
112      "-key-length value    cipher key length in bits: 256, 512, 1024, or 2048",
113      "-keyring filename    get private key from this keyring",
114      "-level value         entropy level: 1 (less entropy) to 9 (more entropy)",
115      "-list type           print a list of supported option arguments",
116      "-log format          format of debugging information",
117      "-mode type           mode of enciphering",
118      "-passphrase filename get the passphrase from this file",
119      "-properties filename put cipher properties to this file",
120      "-random hash         strengthen random data with this hash",
121      "-true-random         strengthen enciphering with true random numbers",
122      "-verbose             print detailed information about the secure content",
123      "-version             print version information",
124      (char *) NULL
125    };
126
127  const char
128    **p;
129
130  (void) fprintf(stdout,"Version: %s\n",GetWizardVersion(
131    (unsigned long *) NULL));
132  (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
133  (void) fprintf(stdout,"Usage: %s [options ...] plaintext ciphertext\n",
134    GetClientName());
135  (void) fprintf(stdout,"\nWhere options include:\n");
136  for (p=options; *p != (char *) NULL; p++)
137    (void) fprintf(stdout,"  %s\n",*p);
138  exit(0);
139}
140
141static double StringToDouble(const char *string,const double interval)
142{
143  char
144    *q;
145
146  double
147    scale,
148    value;
149
150  assert(string != (char *) NULL);
151  value=strtod(string,&q);
152  scale=1000.0;
153  if ((*q != '\0') && (tolower((int) ((unsigned char) *(q+1))) == 'i'))
154    scale=1024.0;
155  switch (tolower((int) ((unsigned char) *q)))
156  {
157    case '%': value*=pow(scale,0)*interval/100.0; break;
158    case 'k': value*=pow(scale,1); break;
159    case 'm': value*=pow(scale,2); break;
160    case 'g': value*=pow(scale,3); break;
161    case 't': value*=pow(scale,4); break;
162    case 'p': value*=pow(scale,5); break;
163    case 'e': value*=pow(scale,6); break;
164    case 'z': value*=pow(scale,7); break;
165    case 'y': value*=pow(scale,8); break;
166    defaultbreak;
167  }
168  return(value);
169}
170
171WizardExport WizardBooleanType EncipherCommand(int argc,char **argv,
172  ExceptionInfo *exception)
173{
174#define DestroyCipher() \
175{ \
176  content_info=DestroyContentInfo(content_info); \
177  for (i=0; i < (long) argc; i++) \
178    argv[i]=DestroyString(argv[i]); \
179  argv=(char **) RelinquishWizardMemory(argv); \
180}
181#define ThrowCipherException(asperity,tag,context) \
182{ \
183  (void) ThrowWizardException(exception,GetWizardModule(),asperity,tag, \
184    context); \
185  DestroyCipher(); \
186  return(WizardFalse); \
187}
188#define ThrowInvalidArgumentException(option,argument) \
189{ \
190  (void) ThrowWizardException(exception,GetWizardModule(),OptionError, \
191    "invalid argument: `%s': %s",argument,option); \
192  DestroyCipher(); \
193  return(WizardFalse); \
194}
195
196  const char
197    *cipher_filename,
198    *option,
199    *plain_filename;
200
201  ContentInfo
202    *content_info;
203
204  long
205    type;
206
207  register long
208    i;
209
210  WizardBooleanType
211    compress,
212    status,
213    verbose;
214
215  /*
216    Parse command-line options.
217  */
218  if (argc == 2)
219    {
220      option=argv[1];
221      if ((LocaleCompare("version",option+1) == 0) ||
222          (LocaleCompare("-version",option+1) == 0))
223        {
224          (void) fprintf(stdout,"Version: %s\n",GetWizardVersion(
225            (unsigned long *) NULL));
226          (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
227          return(WizardTrue);
228        }
229    }
230  if (argc < 3)
231    EncipherUsage();
232  status=ExpandFilenames(&argc,&argv);
233  content_info=AcquireContentInfo();
234  if (status == WizardFalse)
235    ThrowCipherException(ResourceError,"memory allocation failed: `%s'",
236      strerror(errno));
237  plain_filename=(const char *) NULL;
238  cipher_filename=(const char *) NULL;
239  compress=WizardTrue;
240  verbose=WizardFalse;
241  for (i=1; i < (long) argc; i++)
242  {
243    option=argv[i];
244    if (IsWizardOption(option) == WizardFalse)
245      {
246        if (plain_filename == (char *) NULL)
247          plain_filename=option;
248        else
249          if (cipher_filename == (char *) NULL)
250            cipher_filename=option;
251          else
252            EncipherUsage();
253        continue;
254      }
255    switch (*(option+1))
256    {
257      case '(':
258      {
259        if (LocaleCompare(option+1,"(de)compress") == 0)
260          {
261            compress=(*option == '-') ? WizardTrue : WizardFalse;
262            break;
263          }
264        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
265          option);
266        break;
267      }
268      case 'a':
269      {
270        if (LocaleCompare("authenticate",option+1) == 0)
271          {
272            long
273               method;
274
275            if (*option == '+')
276              break;
277            i++;
278            if (i == (long) argc)
279              ThrowCipherException(OptionError,"missing authentication method: "
280                "`%s'",option);
281            method=ParseWizardOption(WizardAuthenticateOptions,WizardFalse,
282              argv[i]);
283            if (method < 0)
284              ThrowCipherException(OptionFatalError,"unrecognized "
285                "authentication method: `%s'",argv[i]);
286            content_info->authenticate_method=(AuthenticateMethod) method;
287            if (method == PublicAuthenticateMethod)
288              ThrowCipherException(OptionFatalError,"Public authentication "
289                "method not available yet: `%s'",argv[i]);
290            break;
291          }
292        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
293          option);
294        break;
295      }
296      case 'c':
297      {
298        if (LocaleCompare("cipher",option+1) == 0)
299          {
300            if (*option == '+')
301              break;
302            i++;
303            if (i == (long) argc)
304              ThrowCipherException(OptionError,"missing cipher type: `%s'",
305                option);
306            type=ParseWizardOption(WizardCipherOptions,WizardFalse,argv[i]);
307            if (type < 0)
308              ThrowCipherException(OptionFatalError,"unrecognized cipher "
309                "type: `%s'",argv[i]);
310            content_info->cipher=(CipherType) type;
311            break;
312          }
313        if (LocaleCompare(option,"-chunksize") == 0)
314          {
315            char
316              *p;
317
318            if (*option == '+')
319              break;
320            i++;
321            if (i == (long) argc)
322              ThrowCipherException(OptionError,"missing chunk size: `%s'",
323                option);
324            (void) strtod(argv[i],&p);
325            if (p == argv[i])
326              ThrowInvalidArgumentException(option,argv[i]);
327            content_info->chunksize=(size_t) StringToDouble(argv[i],100.0);
328            break;
329          }
330        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
331          option);
332        break;
333      }
334      case 'd':
335      {
336        if (LocaleCompare(option,"-debug") == 0)
337          {
338            LogEventType
339              event_mask;
340
341            i++;
342            if (i == (long) argc)
343              ThrowCipherException(OptionError,"missing log event mask: `%s'",
344                option);
345            event_mask=SetLogEventMask(argv[i]);
346            if (event_mask == UndefinedEvents)
347              ThrowCipherException(OptionFatalError,"unrecognized log event "
348                "type: `%s'",argv[i]);
349            break;
350          }
351        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
352          option);
353        break;
354      }
355      case 'e':
356      {
357        if (LocaleCompare("entropy",option+1) == 0)
358          {
359            if (*option == '+')
360              break;
361            i++;
362            if (i == (long) argc)
363              ThrowCipherException(OptionError,"missing entropy type: `%s'",
364                option);
365            type=ParseWizardOption(WizardEntropyOptions,WizardFalse,argv[i]);
366            if (type < 0)
367              ThrowCipherException(OptionFatalError,"unrecognized entropy "
368                "type: `%s'",argv[i]);
369            content_info->entropy=(EntropyType) type;
370            break;
371          }
372        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
373          option);
374        break;
375      }
376      case 'h':
377      {
378        if (LocaleCompare("hmac",option+1) == 0)
379          {
380            long
381              type;
382
383            if (*option == '+')
384              break;
385            i++;
386            if (i == (long) argc)
387              ThrowCipherException(OptionError,"missing HMAC hash: `%s'",
388                option);
389            type=ParseWizardOption(WizardHashOptions,WizardFalse,argv[i]);
390            if (type < 0)
391              ThrowCipherException(OptionFatalError,"unrecognized HMAC hash: "
392                "`%s'",argv[i]);
393            content_info->hmac=(HashType) type;
394            break;
395          }
396        if ((LocaleCompare("help",option+1) == 0) ||
397            (LocaleCompare("-help",option+1) == 0))
398          EncipherUsage();
399        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
400          option);
401        break;
402      }
403      case 'k':
404      {
405        if (LocaleCompare("key",option+1) == 0)
406          {
407            long
408              type;
409
410            if (*option == '+')
411              break;
412            i++;
413            if (i == (long) argc)
414              ThrowCipherException(OptionError,"missing key hash: `%s'",option);
415            type=ParseWizardOption(WizardHashOptions,WizardFalse,argv[i]);
416            if (type < 0)
417              ThrowCipherException(OptionFatalError,"unrecognized key hash: "
418                "`%s'",argv[i]);
419            content_info->key_hash=(HashType) type;
420            break;
421          }
422        if (LocaleCompare("key-length",option+1) == 0)
423          {
424            if (*option == '+')
425              break;
426            i++;
427            if (i == (long) argc)
428              ThrowCipherException(OptionError,"missing key length: `%s'",
429                option);
430            content_info->key_length=(unsigned int) strtod(option,(char **)
431              NULL);
432            break;
433          }
434        if (LocaleCompare("keyring",option+1) == 0)
435          {
436            if (*option == '+')
437              break;
438            i++;
439            if (i == (long) argc)
440              ThrowCipherException(OptionError,"missing keyring filename: `%s'",
441                option);
442            content_info->keyring=ConstantString(argv[i]);
443            break;
444          }
445        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
446          option);
447        break;
448      }
449      case 'l':
450      {
451        if (LocaleCompare(option,"-level") == 0)
452          {
453            if (*option == '+')
454              break;
455            i++;
456            if (i == (long) argc)
457              ThrowCipherException(OptionError,"missing entropy level: `%s'",
458                option);
459            type=ParseWizardOption(WizardEntropyLevelOptions,WizardFalse,
460              argv[i]);
461            if (type < 0)
462              ThrowCipherException(OptionFatalError,"unrecognized entropy "
463                "level: `%s'",argv[i]);
464            content_info->level=(unsigned int) type;
465            break;
466          }
467        if (LocaleCompare(option,"-list") == 0)
468          {
469            long
470              list;
471
472            if (*option == '+')
473              break;
474            i++;
475            if (i == (long) argc)
476              ThrowCipherException(OptionError,"missing list type: `%s'",
477                option);
478            if (LocaleCompare(argv[i],"configure") == 0)
479              {
480                (void) ListConfigureInfo((FILE *) NULL,exception);
481                Exit(0);
482              }
483            list=ParseWizardOption(WizardListOptions,WizardFalse,argv[i]);
484            if (list < 0)
485              ThrowCipherException(OptionFatalError,"unrecognized list type: "
486                "`%s'",argv[i]);
487            (void) ListWizardOptions((FILE *) NULL,(WizardOption) list,
488              exception);
489            Exit(0);
490          }
491        if (LocaleCompare("log",option+1) == 0)
492          {
493            if (*option == '+')
494              break;
495            i++;
496            if ((i == (long) argc) ||
497                (strchr(argv[i],'%') == (char *) NULL))
498              ThrowCipherException(OptionFatalError,"missing argument: `%s'",
499                option);
500            break;
501          }
502        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
503          option);
504        break;
505      }
506      case 'm':
507      {
508        if (LocaleCompare("mode",option+1) == 0)
509          {
510            long
511              type;
512
513            if (*option == '+')
514              break;
515            i++;
516            if (i == (long) argc)
517              ThrowCipherException(OptionError,"missing cipher mode: `%s'",
518                option);
519            type=ParseWizardOption(WizardModeOptions,WizardFalse,argv[i]);
520            if (type < 0)
521              ThrowCipherException(OptionFatalError,"unrecognized cipher "
522                "mode: `%s'",argv[i]);
523            content_info->mode=(CipherMode) type;
524            break;
525          }
526        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
527          option);
528        break;
529      }
530      case 'p':
531      {
532        if (LocaleCompare("passphrase",option+1) == 0)
533          {
534            if (*option == '+')
535              break;
536            i++;
537            if (i == (long) argc)
538              ThrowCipherException(OptionError,"missing passphrase filename: "
539                "`%s'",option);
540            content_info->passphrase=ConstantString(argv[i]);
541            break;
542          }
543        if (LocaleCompare("properties",option+1) == 0)
544          {
545            if (*option == '+')
546              break;
547            i++;
548            if (i == (long) argc)
549              ThrowCipherException(OptionError,"missing properties filename: "
550                "`%s'",option);
551            content_info->properties=ConstantString(argv[i]);
552            break;
553          }
554        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
555          option);
556        break;
557      }
558      case 't':
559      {
560        if (LocaleCompare(option+1,"true-random") == 0)
561          {
562            SetRandomTrueRandom(*option == '-' ? WizardTrue : WizardFalse);
563            break;
564          }
565        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
566          option);
567        break;
568      }
569      case 'v':
570      {
571        if (LocaleCompare(option+1,"verbose") == 0)
572          {
573            verbose=(*option == '-') ? WizardTrue : WizardFalse;
574            break;
575          }
576        if (LocaleCompare(option,"-version") == 0)
577          {
578            (void) fprintf(stdout,"Version: %s\n",GetWizardVersion(
579              (unsigned long *) NULL));
580            (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
581            exit(0);
582          }
583        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
584          option);
585        break;
586      }
587      default:
588      {
589        ThrowCipherException(OptionFatalError,"unrecognized option: `%s'",
590          option);
591        break;
592      }
593    }
594  }
595  /*
596    Encipher content.
597  */
598  if ((plain_filename == (char *) NULL) ||
599      (cipher_filename == (char *) NULL))
600    EncipherUsage();
601  content_info->content=ConstantString(plain_filename);
602  status=EncipherContent(content_info,plain_filename,cipher_filename,
603    compress,exception);
604  if ((status != WizardFalse) && (verbose != WizardFalse))
605    (void) PrintCipherProperties(content_info,stdout);
606  /*
607    Free resources.
608  */
609  DestroyCipher();
610  return(status);
611}
612
613/*
614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
615%                                                                             %
616%                                                                             %
617%                                                                             %
618%   E n c i p h e r C o n t e n t                                               %
619%                                                                             %
620%                                                                             %
621%                                                                             %
622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623%
624%  EncipherContent() reads plaintext from a file and writes it as ciphertext.
625%
626%  The format of the EncipherContent method is:
627%
628%      WizardBooleanType EncipherContent(ContentInfo *content_info,
629%        const char *plain_filename,const char *cipher_filename,
630%        const WizardBooleanType compress,ExceptionInfo *exception)
631%
632%  A description of each parameter follows:
633%
634%    o content_info: the cipher options.
635%
636%    o plain_filename: the plaintext filename.
637%
638%    o cipher_filename: the ciphertext filename.
639%
640%    o compress: automagically (de)compress BZIP and ZIP files.
641%
642%    o exception: return any exceptions in this structure.
643%
644*/
645static WizardBooleanType EncipherContent(ContentInfo *content_info,
646  const char *plain_filename,const char *cipher_filename,
647  const WizardBooleanType compress,ExceptionInfo *exception)
648{
649#define ThrowEncipherContentException(asperity,tag,context) \
650{ \
651  (void) ThrowWizardException(exception,GetWizardModule(),asperity, \
652    tag,context,strerror(errno)); \
653  return(WizardFalse); \
654}
655
656  char
657    *cipher_packet,
658    *cipher_rdf,
659    *digest,
660    message[MaxTextExtent],
661    timestamp[MaxTextExtent];
662
663  const StringInfo
664    *chaos,
665    *hmac;
666
667  const struct stat
668    *properties;
669
670  HashInfo
671    *hash_info;
672
673  size_t
674    length,
675    pad;
676
677  ssize_t
678    count;
679
680  StringInfo
681    *ciphertext,
682    *plaintext;
683
684  unsigned long
685    blocksize;
686
687  WizardBooleanType
688    status;
689
690  /*
691    Open plaintext and ciphertext content files.
692  */
693  content_info->plainblob=OpenBlob(plain_filename,ReadBinaryBlobMode,compress,
694    exception);
695  if (content_info->plainblob == (BlobInfo *) NULL)
696    return(WizardFalse);
697  content_info->cipherblob=OpenBlob(cipher_filename,WriteBinaryBlobMode,
698    compress,exception);
699  if (content_info->cipherblob == (BlobInfo *) NULL)
700    return(WizardFalse);
701  content_info->cipher_info=AcquireCipherInfo(content_info->cipher,
702    content_info->mode);
703  content_info->authenticate_info=AcquireAuthenticateInfo(
704    content_info->authenticate_method,content_info->keyring,
705    content_info->key_hash);
706  if (content_info->passphrase != (char *) NULL)
707    SetAuthenticatePassphrase(content_info->authenticate_info,
708      content_info->passphrase);
709  SetAuthenticateKeyLength(content_info->authenticate_info,
710    content_info->key_length);
711  status=GenerateAuthenticateKey(content_info->authenticate_info,exception);
712  if (status == WizardFalse)
713    return(WizardFalse);
714  content_info->id=StringInfoToHexString(GetAuthenticateId(
715    content_info->authenticate_info));
716  SetCipherKey(content_info->cipher_info,GetAuthenticateKey(
717    content_info->authenticate_info));
718  content_info->nonce=StringInfoToHexString(GetCipherNonce(
719    content_info->cipher_info));
720  content_info->random_info=AcquireRandomInfo(content_info->random_hash);
721  properties=GetBlobProperties(content_info->plainblob);
722  content_info->access_date=properties->st_atime;
723  content_info->modify_date=properties->st_mtime;
724  content_info->create_date=properties->st_ctime;
725  /*
726    Generate cipher RDF blob.
727  */
728  cipher_rdf=AcquireString("<rdf:RDF xmlns:rdf=\""
729    "http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n");
730  (void) ConcatenateString(&cipher_rdf,"         xmlns:cipher=\""
731     "http://www.wizards-toolkit.org/cipher/1.0/\">\n");
732  (void) ConcatenateString(&cipher_rdf,"  <cipher:Content rdf:about=\"");
733  (void) ConcatenateString(&cipher_rdf,plain_filename);
734  (void) ConcatenateString(&cipher_rdf,"\">\n");
735  (void) FormatWizardString(message,MaxTextExtent,
736    "    <cipher:type>%s</cipher:type>\n",WizardOptionToMnemonic(
737    WizardCipherOptions,content_info->cipher));
738  (void) ConcatenateString(&cipher_rdf,message);
739  (void) FormatWizardString(message,MaxTextExtent,
740    "    <cipher:mode>%s</cipher:mode>\n",WizardOptionToMnemonic(
741    WizardModeOptions,content_info->mode));
742  (void) ConcatenateString(&cipher_rdf,message);
743  (void) FormatWizardString(message,MaxTextExtent,
744    "    <cipher:nonce>%s</cipher:nonce>\n",content_info->nonce);
745  (void) ConcatenateString(&cipher_rdf,message);
746  (void) FormatWizardString(message,MaxTextExtent,
747    "    <cipher:authenticate>%s</cipher:authenticate>\n",
748    WizardOptionToMnemonic(WizardAuthenticateOptions,
749    content_info->authenticate_method));
750  (void) ConcatenateString(&cipher_rdf,message);
751  (void) FormatWizardString(message,MaxTextExtent,
752    "    <cipher:id>%s</cipher:id>\n",content_info->id);
753  (void) ConcatenateString(&cipher_rdf,message);
754  (void) FormatWizardString(message,MaxTextExtent,
755    "    <cipher:key-hash>%s</cipher:key-hash>\n",WizardOptionToMnemonic(
756    WizardHashOptions,content_info->key_hash));
757  (void) ConcatenateString(&cipher_rdf,message);
758  (void) FormatWizardString(message,MaxTextExtent,
759    "    <cipher:key-length>%u</cipher:key-length>\n",content_info->key_length);
760  (void) ConcatenateString(&cipher_rdf,message);
761  (void) FormatWizardString(message,MaxTextExtent,
762    "    <cipher:entropy>%s</cipher:entropy>\n",WizardOptionToMnemonic(
763    WizardEntropyOptions,content_info->entropy));
764  (void) ConcatenateString(&cipher_rdf,message);
765  (void) FormatWizardString(message,MaxTextExtent,
766    "    <cipher:level>%u</cipher:level>\n",content_info->level);
767  (void) ConcatenateString(&cipher_rdf,message);
768  (void) FormatWizardString(message,MaxTextExtent,
769    "    <cipher:hmac>%s</cipher:hmac>\n",WizardOptionToMnemonic(
770    WizardHashOptions,content_info->hmac));
771  (void) ConcatenateString(&cipher_rdf,message);
772  (void) FormatWizardString(message,MaxTextExtent,
773    "    <cipher:chunksize>%lu</cipher:chunksize>\n",1UL*
774    content_info->chunksize);
775  (void) ConcatenateString(&cipher_rdf,message);
776  (void) FormatWizardTime(content_info->modify_date,MaxTextExtent,timestamp);
777  (void) FormatWizardString(message,MaxTextExtent,
778    "    <cipher:modify-date>%s</cipher:modify-date>\n",timestamp);
779  (void) ConcatenateString(&cipher_rdf,message);
780  (void) FormatWizardTime(content_info->create_date,MaxTextExtent,timestamp);
781  (void) FormatWizardString(message,MaxTextExtent,
782    "    <cipher:create-date>%s</cipher:create-date>\n",timestamp);
783  (void) ConcatenateString(&cipher_rdf,message);
784  (void) FormatWizardTime(content_info->timestamp,MaxTextExtent,timestamp);
785  (void) FormatWizardString(message,MaxTextExtent,
786    "    <cipher:timestamp>%s</cipher:timestamp>\n",timestamp);
787  (void) ConcatenateString(&cipher_rdf,message);
788  (void) FormatWizardString(message,MaxTextExtent,
789    "    <cipher:protocol>%u.%u</cipher:protocol>\n",
790    content_info->protocol_major,content_info->protocol_minor);
791  (void) ConcatenateString(&cipher_rdf,message);
792  (void) FormatWizardString(message,MaxTextExtent,
793    "    <cipher:version>%s</cipher:version>\n",content_info->version);
794  (void) ConcatenateString(&cipher_rdf,message);
795  (void) ConcatenateString(&cipher_rdf,"  </cipher:Content>\n");
796  (void) ConcatenateString(&cipher_rdf,"</rdf:RDF>\n");
797  /*
798    Wrap cipher RDF in a cipher-packet.
799  */
800  length=strlen(cipher_rdf);
801  hash_info=AcquireHashInfo(SHA256Hash);
802  InitializeHash(hash_info);
803  plaintext=StringToStringInfo(cipher_rdf);
804  UpdateHash(hash_info,plaintext);
805  plaintext=DestroyStringInfo(plaintext);
806  FinalizeHash(hash_info);
807  digest=GetHashHexDigest(hash_info);
808  length=(size_t) FormatWizardString(message,MaxTextExtent,
809    "<?cipherpacket digest=\"%s\" bytes=\"%u\"?>\n",digest,(unsigned int)
810    length);
811  digest=DestroyString(digest);
812  hash_info=DestroyHashInfo(hash_info);
813  cipher_packet=AcquireString(message);
814  (void) ConcatenateString(&cipher_packet,cipher_rdf);
815  cipher_rdf=DestroyString(cipher_rdf);
816  (void) ConcatenateString(&cipher_packet,"<?cipherpacket?>\f\n");
817  length=strlen(cipher_packet);
818  if (content_info->properties == (char *) NULL)
819    count=WriteBlob(content_info->cipherblob,length,(unsigned char *)
820      cipher_packet);
821  else
822    {
823      BlobInfo
824        *properties;
825
826      /*
827        Cipher properties are stored separately from the content.
828      */
829      properties=OpenBlob(content_info->properties,WriteBinaryBlobMode,
830        WizardTrue,exception);
831      if (properties == (BlobInfo *) NULL)
832        return(WizardFalse);
833      count=WriteBlob(properties,length,(unsigned char *) cipher_packet);
834      if (CloseBlob(properties) == WizardTrue)
835        ThrowFileException(exception,FileError,content_info->properties);
836      properties=DestroyBlob(properties);
837    }
838  cipher_packet=DestroyString(cipher_packet);
839  if (count != (ssize_t) length)
840    ThrowEncipherContentException(FileError,"unable to write cipher properties "
841      "`%s': `%s'",cipher_filename);
842  /*
843    Encipher plaintext.
844  */
845  if (content_info->hmac != NoHash)
846    content_info->hmac_info=AcquireHMACInfo(content_info->hmac);
847  content_info->entropy_info=(EntropyInfo *) NULL;
848  if (content_info->entropy != NoEntropy)
849    content_info->entropy_info=AcquireEntropyInfo(content_info->entropy,
850      content_info->level);
851  pad=0;
852  blocksize=GetCipherBlocksize(content_info->cipher_info);
853  ciphertext=(StringInfo *) NULL;
854  for (plaintext=AcquireStringInfo(content_info->chunksize); ; )
855  {
856    SetStringInfoLength(plaintext,content_info->chunksize);
857    count=ReadBlobChunk(content_info->plainblob,content_info->chunksize,
858      GetStringInfoDatum(plaintext));
859    if (count <= 0)
860      break;
861    length=(size_t) count;
862    SetStringInfoLength(plaintext,length);
863    if (content_info->hmac != NoHash)
864      {
865        ConstructHMAC(content_info->hmac_info,GetAuthenticateKey(
866          content_info->authenticate_info),plaintext);
867        hmac=GetHMACDigest(content_info->hmac_info);
868        count=WriteBlobChunk(content_info->cipherblob,GetStringInfoLength(hmac),
869          GetStringInfoDatum(hmac));
870        if (count != (ssize_t) GetStringInfoLength(hmac))
871          ThrowEncipherContentException(FileError,"unable to write ciphertext "
872            "`%s': `%s'",cipher_filename);
873      }
874    if (content_info->entropy != NoEntropy)
875      {
876        status=IncreaseEntropy(content_info->entropy_info,plaintext,exception);
877        chaos=GetEntropyChaos(content_info->entropy_info);
878        if (status == WizardFalse)
879          ThrowEncipherContentException(FileError,"unable to increase entropy "
880            "`%s': `%s'",cipher_filename);
881        if (GetStringInfoLength(chaos) > length)
882          count=WriteBlobByte(content_info->cipherblob,(unsigned char)
883            NoEntropy);
884        else
885          {
886            SetStringInfo(plaintext,chaos);
887            SetRandomKey(content_info->random_info,length-GetStringInfoLength(
888              chaos),GetStringInfoDatum(plaintext)+GetStringInfoLength(chaos));
889            count=WriteBlobByte(content_info->cipherblob,(unsigned char)
890              content_info->entropy);
891          }
892        if (count != 1)
893          ThrowEncipherContentException(FileError,"unable to write ciphertext "
894            "`%s': `%s'",cipher_filename);
895      }
896    ciphertext=EncipherCipher(content_info->cipher_info,plaintext);
897    if (content_info->mode != CFBMode)
898      {
899        pad=blocksize-length % blocksize;
900        if (pad != blocksize)
901          length+=pad;
902      }
903    count=WriteBlobChunk(content_info->cipherblob,length,GetStringInfoDatum(
904      ciphertext));
905    if (count != (ssize_t) length)
906      ThrowEncipherContentException(FileError,"unable to write ciphertext "
907        "`%s': `%s'",cipher_filename);
908    if (SyncBlob(content_info->cipherblob) != WizardFalse)
909      ThrowEncipherContentException(FileError,"unable to sync ciphertext `%s': "
910        "`%s'",cipher_filename);
911  }
912  if ((content_info->mode != CFBMode) && (pad == blocksize))
913    {
914      /*
915        Cryptographic padding.
916      */
917      count=WriteBlobChunk(content_info->cipherblob,blocksize,
918        GetStringInfoDatum(ciphertext)+length);
919      if (count != (ssize_t) blocksize)
920        ThrowEncipherContentException(FileError,"unable to write ciphertext "
921          "`%s': `%s'",cipher_filename);
922    }
923  if (CloseBlob(content_info->cipherblob) != WizardFalse)
924    ThrowFileException(exception,FileError,content_info->content);
925  if (CloseBlob(content_info->plainblob) != WizardFalse)
926    ThrowFileException(exception,FileError,content_info->content);
927  plaintext=DestroyStringInfo(plaintext);
928  return(WizardTrue);
929}
930
931/*
932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933%                                                                             %
934%                                                                             %
935%                                                                             %
936%  M a i n                                                                    %
937%                                                                             %
938%                                                                             %
939%                                                                             %
940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941%
942%
943*/
944int main(int argc,char **argv)
945{
946  char
947    *option;
948
949  double
950    elapsed_time,
951    user_time;
952
953  ExceptionInfo
954    *exception;
955
956  register long
957    i;
958
959  TimerInfo
960    *timer;
961
962  unsigned int
963    iterations;
964
965  WizardBooleanType
966    regard_warnings,
967    status;
968
969  WizardsToolkitGenesis(*argv);
970  exception=AcquireExceptionInfo();
971  iterations=1;
972  status=WizardTrue;
973  regard_warnings=WizardFalse;
974  for (i=1; i < (long) (argc-1); i++)
975  {
976    option=argv[i];
977    if ((strlen(option) == 1) || ((*option != '-') && (*option != '+')))
978      continue;
979    if (LocaleCompare("bench",option+1) == 0)
980      iterations=(unsigned int) atol(argv[++i]);
981    if (LocaleCompare("debug",option+1) == 0)
982      (void) SetLogEventMask(argv[++i]);
983    if (LocaleCompare("regard-warnings",option+1) == 0)
984      regard_warnings=WizardTrue;
985  }
986  timer=(TimerInfo *) NULL;
987  if (iterations > 1)
988    timer=AcquireTimerInfo();
989  for (i=0; i < (long) iterations; i++)
990  {
991    status=EncipherCommand(argc,argv,exception);
992    if ((status == WizardFalse) ||
993        (GetExceptionSeverity(exception) != UndefinedException))
994      {
995        if ((GetExceptionSeverity(exception) < ErrorException) &&
996            (regard_warnings == WizardFalse))
997          status=WizardTrue;
998        CatchException(exception);
999      }
1000  }
1001  if (iterations > 1)
1002    {
1003      elapsed_time=GetElapsedTime(timer);
1004      user_time=GetUserTime(timer);
1005      (void) fprintf(stderr,"Performance: %ui %gips %0.3fu %ld:%02ld.%03ld\n",
1006        iterations,1.0*iterations/elapsed_time,user_time,(long)
1007        (elapsed_time/60.0+0.5),(long) floor(fmod(elapsed_time,60.0)),
1008        (long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
1009      timer=DestroyTimerInfo(timer);
1010    }
1011  exception=DestroyExceptionInfo(exception);
1012  WizardsToolkitTerminus();
1013  return(status == WizardFalse ? 1 : 0);
1014}
Note: See TracBrowser for help on using the browser.