summaryrefslogtreecommitdiff
path: root/apps/plugins/lua/lopcodes.c
blob: 4cc745230b79f8c3d916dc992cd5b4ea4352d274 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
** See Copyright Notice in lua.h
*/


#define lopcodes_c
#define LUA_CORE


#include "lopcodes.h"


/* ORDER OP */

const char *const luaP_opnames[NUM_OPCODES+1] = {
  "MOVE",
  "LOADK",
  "LOADBOOL",
  "LOADNIL",
  "GETUPVAL",
  "GETGLOBAL",
  "GETTABLE",
  "SETGLOBAL",
  "SETUPVAL",
  "SETTABLE",
  "NEWTABLE",
  "SELF",
  "ADD",
  "SUB",
  "MUL",
  "DIV",
  "MOD",
  "POW",
  "UNM",
  "NOT",
  "LEN",
  "CONCAT",
  "JMP",
  "EQ",
  "LT",
  "LE",
  "TEST",
  "TESTSET",
  "CALL",
  "TAILCALL",
  "RETURN",
  "FORLOOP",
  "FORPREP",
  "TFORLOOP",
  "SETLIST",
  "CLOSE",
  "CLOSURE",
  "VARARG",
  NULL
};


#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))

const lu_byte luaP_opmodes[NUM_OPCODES] = {
/*       T  A    B       C     mode		   opcode	*/
  opmode(0, 1, OpArgR, OpArgN, iABC) 		/* OP_MOVE */
 ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */
 ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
 ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LOADNIL */
 ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
 ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_GETGLOBAL */
 ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
 ,opmode(0, 0, OpArgK, OpArgN, iABx)		/* OP_SETGLOBAL */
 ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
 ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
 ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
 ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
 ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */
 ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */
 ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */
 ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */
 ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */
 ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */
 ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */
 ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */
 ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */
 ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */
 ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */
 ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
 ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
 ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
 ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TEST */
 ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
 ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
 ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
 ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */
 ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */
 ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */
 ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TFORLOOP */
 ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */
 ,opmode(0, 0, OpArgN, OpArgN, iABC)		/* OP_CLOSE */
 ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
 ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
};

a id='n626' href='#n626'>626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
/* zenutils - Utilities for working with creative firmwares.
 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <iostream>
#include <getpot/GetPot>
#include <cenc.h>
#include <crypt.h>
#include <file.h>
#include <firmware.h>
#include <utils.h>


namespace {
enum command_t
{
    cmd_none = 0,
    cmd_sign,
    cmd_verify,
    cmd_encrypt,
    cmd_decrypt
};

enum mode_t
{
    mode_none = 0,
    mode_cenc,
    mode_fresc,
    mode_tl
};

struct player_info_t
{
    const char* name;
    const char* null_key;  /* HMAC-SHA1 key */
    const char* fresc_key; /* BlowFish key */
    const char* tl_key;    /* BlowFish key */
    bool big_endian;
};
}; /* namespace */


static const char VERSION[] = "0.2";

static const char null_key_v1[]  = "CTL:N0MAD|PDE0.SIGN.";
static const char null_key_v2[]  = "CTL:N0MAD|PDE0.DPMP.";
static const char null_key_v3[]  = "CTL:N0MAD|PDE0.DPFP.";
static const char null_key_v4[]  = "CTL:Z3N07|PDE0.DPMP.";

static const char fresc_key_v1[] = "Copyright (C) CTL. -"
                                   " zN0MAD iz v~p0wderful!";
static const char fresc_key_v2[] = ""; /* Unknown atm */

static const char tl_zvm_key[]   = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Vision:M";
static const char tl_zvm60_key[] = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Vision:M (D"
                                   "VP-HD0004)";
static const char tl_zen_key[]   = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN";
static const char tl_zenxf_key[] = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN X-Fi";
static const char tl_zenmo_key[] = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN Mozaic";
static const char tl_zv_key[]    = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Vision";
static const char tl_zvw_key[]   = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN Vision W";
static const char tl_zm_key[]    = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Micro";
static const char tl_zmp_key[]   = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen MicroPhoto";
static const char tl_zs_key[]    = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Sleek";
static const char tl_zsp_key[]   = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Sleek Photo";
static const char tl_zt_key[]    = "1sN0TM3D az u~may th1nk*"
                                   "Creative Zen Touch";
static const char tl_zx_key[]    = "1sN0TM3D az u~may th1nk*"
                                   "NOMAD Jukebox Zen Xtra";
static const char tl_zenv_key[]  = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN V";
static const char tl_zenvp_key[] = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN V Plus";
static const char tl_zenvv_key[] = "1sN0TM3D az u~may th1nk*"
                                   "Creative ZEN V (Video)";

player_info_t players[] = {
    {"Zen Vision:M", null_key_v2, fresc_key_v1, tl_zvm_key, false},
    {"Zen Vision:M 60GB", null_key_v2, fresc_key_v1, tl_zvm60_key, false},
    {"ZEN", null_key_v4, fresc_key_v2, tl_zen_key, false},
    {"ZEN X-Fi", null_key_v4, fresc_key_v2, tl_zenxf_key, false},
    {"ZEN Mozaic", null_key_v4, fresc_key_v2, tl_zenmo_key, false},
    {"Zen Vision", null_key_v2, fresc_key_v1, tl_zv_key, false},
    {"Zen Vision W", null_key_v2, fresc_key_v1, tl_zvw_key, false},
    {"Zen Micro", null_key_v1, fresc_key_v1, tl_zm_key, true},
    {"Zen MicroPhoto", null_key_v1, fresc_key_v1, tl_zmp_key, true},
    {"Zen Sleek", null_key_v1, fresc_key_v1, tl_zs_key, true},
    {"Zen SleekPhoto", null_key_v1, fresc_key_v1, tl_zsp_key, true},
    {"Zen Touch", null_key_v1, fresc_key_v1, tl_zt_key, true},
    {"Zen Xtra", null_key_v1, fresc_key_v1, tl_zx_key, true},
    {"Zen V", null_key_v3, fresc_key_v1, tl_zenv_key, false},
    {"Zen V Plus", null_key_v3, fresc_key_v1, tl_zenvp_key, false},
    {"Zen V Video", null_key_v3, fresc_key_v1, tl_zenvv_key, false},
    {NULL, NULL, NULL, NULL, false}
};


player_info_t* find_player_info(std::string player)
{
    for (int i = 0; players[i].name != NULL; i++)
    {
        if (!strcasecmp(players[i].name, player.c_str()))
        {
            return &players[i];
        }
    }
    return NULL;
}

void print_version()
{
    std::cout
        << "zen_crypt - A utility for encrypting, decrypting or signing"
           " Creative firmwares." << std::endl
        << "Version " << VERSION << std::endl
        << "Copyright (c) 2007 Rasmus Ry" << std::endl;
}

void print_help()
{
    print_version();
    std::cout << std::endl
        << "Usage: zen_crypt [command] [options]" << std::endl
        << std::endl
        << " Commands:" << std::endl
        << "  -h,--help" << std::endl
        << "      prints this message." << std::endl
        << "  -s,--sign" << std::endl
        << "      signs a given input file." << std::endl
        << "  -v,--verify" << std::endl
        << "      verifies a signed input file." << std::endl
        << "  -e,--encrypt" << std::endl
        << "      encrypts a given input file." << std::endl
        << "  -d,--decrypt" << std::endl
        << "      decrypts a given input file." << std::endl
        << std::endl
        << " Options:" << std::endl
        << "  -V,--verbose" << std::endl
        << "      prints verbose messages." << std::endl
        << "  -b,--big-endian" << std::endl
        << "      specifies that the input is big-endian, default is"
           " little-endian." << std::endl
        << "  -i,--input [file]" << std::endl
        << "      specifies the input file." << std::endl
        << "  -o,--output [file]" << std::endl
        << "      specifies the output file." << std::endl
        << "  -m,--mode [CENC|FRESC|TL]" << std::endl
        << "      specifies which algorithm to use." << std::endl
        << "  -k,--key [player|key]" << std::endl
        << "      specifies which key to use." << std::endl
        << std::endl
        ;
    std::cout << " Players:" << std::endl;
    for (int i = 0; players[i].name != NULL; i++)
    {
        std::cout << "      " << players[i].name;
        if (!i)
            std::cout << " (default)";
        std::cout << std::endl;
    }
}

size_t find_null_signature(shared::bytes& data)
{
    size_t index = data.size();
    if (index < (20 + 8 + 7))
        return 0;
    index -= 20 + 8;
    for (int i = 0; i < 7; i++)
    {
        if (*(dword*)&data[index-i] == 'NULL' ||
            *(dword*)&data[index-i] == 'LLUN')
        {
            return index-i;
        }
    }
    return 0;
}


bool sign(shared::bytes& data, player_info_t* pi, const std::string& file,
          bool verbose)
{
    if (verbose)
        std::cout << "[*] Checking for the presence of an existing"
                     " NULL signature..." << std::endl;
    size_t index = find_null_signature(data);
    if (index)
    {
        if (verbose)
            std::cout << "[*] Found NULL signature at: 0x"
                      << std::hex << index << std::endl;

        if (verbose)
            std::cout << "[*] Computing digest..." << std::endl;

        shared::bytes digest(20);
        if (!zen::hmac_sha1_calc((const byte*)pi->null_key,
                                 strlen(pi->null_key)+1, &data[0], index,
                                 &digest[0], NULL))
        {
            std::cerr << "Failed to compute digest." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, data, true))
        {
            std::cerr << "Failed to write file data." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing digest data..." << std::endl;

        if (!shared::write_file(file, digest, false, index+8))
        {
            std::cerr << "Failed to write digest data." << std::endl;
            return false;
        }
    }
    else
    {
        if (verbose)
            std::cout << "[*] Computing digest..." << std::endl;

        shared::bytes signature(20+8);
        if (!zen::hmac_sha1_calc((const byte*)pi->null_key,
                                 strlen(pi->null_key)+1, &data[0], data.size(),
                                 &signature[8], NULL))
        {
            std::cerr << "Failed to compute digest." << std::endl;
            return false;
        }


        zen::firmware_header_t header = {'NULL', 20};
        if (pi->big_endian)
        {
            header.tag = shared::swap(header.tag);
            header.size = shared::swap(header.size);
        }
        memcpy(&signature[0], &header, sizeof(zen::firmware_header_t));

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, data, true))
        {
            std::cerr << "Failed to write file data." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing signature data..." << std::endl;

        if (!shared::write_file(file, signature, false, data.size()))
        {
            std::cerr << "Failed to write signature data." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Ensuring that the file length is"
                         " 32-bit aligned..." << std::endl;

        int length = data.size() + signature.size();
        int align = length % 4;
        if (align)
        {
            shared::bytes padding(4 - align, 0);
            if (!shared::write_file(file, padding, false, length))
            {
                std::cerr << "Failed to write padding data." << std::endl;
                return false;
            }
        }
    }

    return true;
}

bool verify(shared::bytes& data, player_info_t* pi, bool verbose)
{
    if (verbose)
        std::cout << "[*] Checking for the presence of an existing"
                     " NULL signature..." << std::endl;
    size_t index = find_null_signature(data);
    if (!index)
    {
        std::cerr << "No NULL signature present in the input file."
                  << std::endl;
        return false;
    }
    if (verbose)
        std::cout << "[*] Found NULL signature at: 0x"
                  << std::hex << index << std::endl;

    if (verbose)
        std::cout << "[*] Computing digest..." << std::endl;

    byte digest[20];
    if (!zen::hmac_sha1_calc((const byte*)pi->null_key, strlen(pi->null_key)+1,
                             &data[0], index, digest, NULL))
    {
        std::cerr << "Failed to compute digest." << std::endl;
        return false;
    }

    if (verbose)
        std::cout << "[*] Verifying NULL signature digest..." << std::endl;

    if (memcmp(&digest[0], &data[index+8], 20))
    {
        std::cerr << "The NULL signature contains an incorrect digest."
                  << std::endl;
        return false;
    }

    return true;
}

bool encrypt(shared::bytes& data, int mode, player_info_t* pi,
             const std::string& file, bool verbose)
{
    if (mode == mode_cenc)
    {
        if (verbose)
            std::cout << "[*] Encoding input file..." << std::endl;

        shared::bytes outbuf(data.size() * 2);
        int len = zen::cenc_encode(&data[0], data.size(), &outbuf[0], outbuf.size());
        if (!len)
        {
            std::cerr << "Failed to encode the input file." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing decoded length to file..." << std::endl;

        shared::bytes length(sizeof(dword));
        *(dword*)&length[0] = pi->big_endian ? shared::swap(data.size()) : data.size();
        if (!shared::write_file(file, length, true))
        {
            std::cerr << "Failed to write the file data." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, outbuf, sizeof(dword), len))
        {
            std::cerr << "Failed to write the file data." << std::endl;
            return false;
        }
    }
    else if (mode == mode_fresc)
    {
        if (verbose)
            std::cout << "[*] Encrypting input file..." << std::endl;

        dword iv[2] = {shared::swap(data.size()), 0};
        if (!zen::bf_cbc_encrypt((const byte*)pi->fresc_key,
                                 strlen(pi->fresc_key)+1, &data[0],
                                 data.size(), (const byte*)iv))
        {
            std::cerr << "Failed to encrypt the input file." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, data, true))
        {
            std::cerr << "Failed to save the output file." << std::endl;
            return false;
        }
    }
    else if (mode == mode_tl)
    {
        if (verbose)
            std::cout << "[*] Encoding input file..." << std::endl;

        shared::bytes outbuf(data.size() * 2);
        *(dword*)&outbuf[0] = pi->big_endian ? shared::swap(data.size()) : data.size();
        int len = zen::cenc_encode(&data[0], data.size(),
                                  &outbuf[sizeof(dword)],
                                  outbuf.size()-sizeof(dword));
        if (!len)
        {
            std::cerr << "Failed to encode the input file." << std::endl;
            return false;
        }
        len += sizeof(dword);

        int align = len % 8;
        align = align ? (8 - align) : 0;
        len += align;

        if (verbose)
            std::cout << "[*] Encrypting encoded data..." << std::endl;

        dword iv[2] = {0, shared::swap(len)};
        if (!zen::bf_cbc_encrypt((const byte*)pi->tl_key, strlen(pi->tl_key)+1,
                            &outbuf[0], len, (const byte*)iv))
        {
            std::cerr << "Failed to encrypt the input file." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, outbuf, true, 0, len))
        {
            std::cerr << "Failed to save the output file." << std::endl;
            return false;
        }
    }
    else
    {
        std::cerr << "Invalid mode specified." << std::endl;
        return false;
    }

    return true;
}

bool decrypt(shared::bytes& data, int mode, player_info_t* pi,
             const std::string& file, bool verbose)
{
    if (mode == mode_cenc)
    {
        dword length = *(dword*)&data[0];
        length = pi->big_endian ? shared::swap(length) : length;

        if (verbose)
            std::cout << "[*] Decoding input file..." << std::endl;

        shared::bytes outbuf(length);
        if (!zen::cenc_decode(&data[sizeof(dword)], data.size()-sizeof(dword),
                              &outbuf[0], length))
        {
            std::cerr << "Failed to decode the input file." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, outbuf, true))
        {
            std::cerr << "Failed to write the file data." << std::endl;
            return false;
        }
    }
    else if (mode == mode_fresc)
    {
        if (verbose)
            std::cout << "[*] Decrypting input file..." << std::endl;

        dword iv[2] = {shared::swap(data.size()), 0};
        if (!zen::bf_cbc_decrypt((const byte*)pi->fresc_key,
                                 strlen(pi->fresc_key)+1, &data[0],
                                 data.size(), (const byte*)iv))
        {
            std::cerr << "Failed to decrypt the input file." << std::endl;
            return false;
        }
        
        if (*(dword*)&data[0] != 'EDOC' &&
            *(dword*)&data[0] != 'CODE')
        {
            std::cerr << "Failed to decode the input file." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, data, true))
        {
            std::cerr << "Failed to save the output file." << std::endl;
            return false;
        }
    }
    else if (mode == mode_tl)
    {
        if (verbose)
            std::cout << "[*] Decrypting input file..." << std::endl;

        dword iv[2] = {0, shared::swap(data.size())};
        if (!zen::bf_cbc_decrypt((const byte*)pi->tl_key, strlen(pi->tl_key)+1,
                            &data[0], data.size(), (const byte*)iv))
        {
            std::cerr << "Failed to decrypt the input file." << std::endl;
            return false;
        }

        dword length = *(dword*)&data[0];
        length = pi->big_endian ? shared::swap(length) : length;
        if (length > (data.size() * 3))
        {
            std::cerr << "Decrypted length is unexpectedly large: "
                      << std::hex << length
                      << " Check the endian and key settings." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Decoding decrypted data..." << std::endl;

        shared::bytes outbuf(length);
        if (!zen::cenc_decode(&data[sizeof(dword)], data.size()-sizeof(dword),
                              &outbuf[0], length))
        {
            std::cerr << "Failed to decode the input file." << std::endl;
            return false;
        }

        if (verbose)
            std::cout << "[*] Writing file data..." << std::endl;

        if (!shared::write_file(file, outbuf, true))
        {
            std::cerr << "Failed to save the output file." << std::endl;
            return false;
        }
    }
    else
    {
        std::cerr << "Invalid mode specified." << std::endl;
        return false;
    }

    return true;
}

int process_arguments(int argc, char*argv[])
{
    /*
      --------------------------------------------------------------------
       Parse input variables.
      --------------------------------------------------------------------
    */

    GetPot cl(argc, argv);
    if (cl.size() == 1 || cl.search(2, "-h", "--help"))
    {
        print_help();
        return 1;
    }

    int command = cmd_none;
    if (cl.search(2, "-s", "--sign"))
        command = cmd_sign;
    else if (cl.search(2, "-v", "--verify"))
        command = cmd_verify;
    else if (cl.search(2, "-e", "--encrypt"))
        command = cmd_encrypt;
    else if (cl.search(2, "-d", "--decrypt"))
        command = cmd_decrypt;

    if (command == cmd_none)
    {
        std::cerr << "No command specified." << std::endl;
        return 2;
    }

    int mode = mode_none;
    if (command == cmd_encrypt || command == cmd_decrypt)
    {
        if (!cl.search(2, "-m", "--mode"))
        {
            std::cerr << "The specified command requires that"
                         " a mode is specified."
                      << std::endl;
            return 3;
        }
        std::string name = cl.next("");
        if (!name.empty())
        {
            if (!strcasecmp(name.c_str(), "CENC"))
                mode = mode_cenc;
            else if (!strcasecmp(name.c_str(), "FRESC"))
                mode = mode_fresc;
            else if (!strcasecmp(name.c_str(), "TL"))
                mode = mode_tl;
        }
        if (mode == mode_none)
        {
            std::cerr << "Invalid mode specified." << std::endl;
            return 4;
        }
    }

    bool verbose = false;
    if (cl.search(2, "-V", "--verbose"))
        verbose = true;

    bool big_endian = false;
    if (cl.search(2, "-b", "--big-endian"))
        big_endian = true;

    std::string infile;
    if (cl.search(2, "-i", "--input"))
        infile = cl.next("");
    if (infile.empty())
    {
        std::cerr << "An input file must be specified." << std::endl;
        return 5;
    }