Skip to content

Instantly share code, notes, and snippets.

@ignatk
Last active August 29, 2015 14:01
Show Gist options
  • Save ignatk/239ff4772af4342ea42c to your computer and use it in GitHub Desktop.
Save ignatk/239ff4772af4342ea42c to your computer and use it in GitHub Desktop.
Utility to convert IIT keys to proper format
/* Copyright (c) 2014, Ignat Korchagin <ignat.korchagin@gmail.com>, Ilya Petrov <ilya.muromec@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <gosthash.h>
typedef struct IIT_key_info_params_st
{
ASN1_OCTET_STRING *mac;
ASN1_OCTET_STRING *aux;
} IIT_key_info_params;
DECLARE_ASN1_FUNCTIONS(IIT_key_info_params)
ASN1_SEQUENCE(IIT_key_info_params) =
{
ASN1_SIMPLE(IIT_key_info_params, mac, ASN1_OCTET_STRING),
ASN1_SIMPLE(IIT_key_info_params, aux, ASN1_OCTET_STRING)
}ASN1_SEQUENCE_END(IIT_key_info_params)
IMPLEMENT_ASN1_FUNCTIONS(IIT_key_info_params)
typedef struct IIT_key_info_st
{
ASN1_OBJECT *oid;
IIT_key_info_params *params;
} IIT_key_info;
DECLARE_ASN1_FUNCTIONS(IIT_key_info)
ASN1_SEQUENCE(IIT_key_info) =
{
ASN1_SIMPLE(IIT_key_info, oid, ASN1_OBJECT),
ASN1_SIMPLE(IIT_key_info, params, IIT_key_info_params)
}ASN1_SEQUENCE_END(IIT_key_info)
IMPLEMENT_ASN1_FUNCTIONS(IIT_key_info)
typedef struct IIT_key_st
{
IIT_key_info *info;
ASN1_OCTET_STRING *encrypted_key;
} IIT_key;
DECLARE_ASN1_FUNCTIONS(IIT_key)
ASN1_SEQUENCE(IIT_key) =
{
ASN1_SIMPLE(IIT_key, info, IIT_key_info),
ASN1_SIMPLE(IIT_key, encrypted_key, ASN1_OCTET_STRING)
}ASN1_SEQUENCE_END(IIT_key)
IMPLEMENT_ASN1_FUNCTIONS(IIT_key)
static long read_file(const char *path, unsigned char **output)
{
FILE *fp = fopen(path, "rb");
unsigned char *data = NULL;
long size, res = -1;
size_t bytes_read;
if (!fp)
return res;
if (!output)
goto err;
if (fseek(fp, 0, SEEK_END))
goto err;
size = ftell(fp);
if (size <= 0)
goto err;
if (fseek(fp, 0, SEEK_SET))
goto err;
data = malloc(size);
if (!data)
goto err;
bytes_read = fread(data, 1, size, fp);
if (bytes_read != size)
goto err;
res = size;
*output = data;
data = NULL;
err:
if (data)
free(data);
fclose (fp);
return res;
}
static gost_subst_block ua1_sbox =
{
{0x1, 0x2, 0x3, 0xe, 0x6, 0xd, 0xb, 0x8, 0xf, 0xa, 0xc, 0x5, 0x7, 0x9, 0x0, 0x4},
{0x3, 0x8, 0xb, 0x5, 0x6, 0x4, 0xe, 0xa, 0x2, 0xc, 0x1, 0x7, 0x9, 0xf, 0xd, 0x0},
{0x2, 0x8, 0x9, 0x7, 0x5, 0xf, 0x0, 0xb, 0xc, 0x1, 0xd, 0xe, 0xa, 0x3, 0x6, 0x4},
{0xf, 0x8, 0xe, 0x9, 0x7, 0x2, 0x0, 0xd, 0xc, 0x6, 0x1, 0x5, 0xb, 0x4, 0x3, 0xa},
{0x3, 0x8, 0xd, 0x9, 0x6, 0xb, 0xf, 0x0, 0x2, 0x5, 0xc, 0xa, 0x4, 0xe, 0x1, 0x7},
{0xf, 0x6, 0x5, 0x8, 0xe, 0xb, 0xa, 0x4, 0xc, 0x0, 0x3, 0x7, 0x2, 0x9, 0x1, 0xd},
{0x8, 0x0, 0xc, 0x4, 0x9, 0x6, 0x7, 0xb, 0x2, 0x3, 0x1, 0xf, 0x5, 0xe, 0xa, 0xd},
{0xa, 0x9, 0xd, 0x6, 0xe, 0xb, 0x4, 0x5, 0xf, 0x1, 0x3, 0xc, 0x7, 0x0, 0x8, 0x2}
};
static void password_to_key(const char *password, unsigned char *key)
{
gost_ctx gctx;
gost_hash_ctx hctx;
int i;
memset(&gctx, 0, sizeof(gost_ctx));
memset(&hctx, 0, sizeof(gost_hash_ctx));
hctx.cipher_ctx = &gctx;
gost_init(&gctx, &ua1_sbox);
hash_block(&hctx, (const byte *)password, strlen(password));
finish_hash(&hctx, key);
for (i = 1; i < 10000; i++)
{
start_hash(&hctx);
hash_block(&hctx, key, 32);
finish_hash(&hctx, key);
}
start_hash(&hctx);
}
static void decrypt_data(unsigned char *data, int length, const unsigned char *key, const unsigned char *aux)
{
gost_ctx gctx;
int blocks = length / 8;
unsigned char last_block[8];
gost_init(&gctx, &ua1_sbox);
gost_key(&gctx, key);
gost_dec(&gctx, data, data, blocks);
memcpy(last_block, data + (blocks * 8), 4);
memcpy(last_block + 4, aux, 4);
gost_dec(&gctx, last_block, last_block, 1);
memcpy(data + (blocks * 8), last_block, 4);
gost_destroy(&gctx);
}
static int check_mac(unsigned char *data, int length, const unsigned char *key, const unsigned char *mac)
{
gost_ctx gctx;
unsigned char computed_mac[4];
gost_init(&gctx, &ua1_sbox);
gost_key(&gctx, key);
gost_mac(&gctx, 32, data, length, computed_mac);
return memcmp(mac, computed_mac, sizeof(computed_mac));
}
static void print_usage(void)
{
printf("Usage: convertiit <input_file> <output_file> <password>\n");
}
static const char iit_key_oid[] = {0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x97, 0x46, 0x01, 0x01, 0x01, 0x02};
int main(int argc, char **argv)
{
IIT_key *key = NULL;
unsigned char *iit_key_encoded = NULL;
const unsigned char *encoded_data = NULL;
unsigned char sk[32];
EVP_PKEY *pkey = NULL;
BIO *out = NULL;
long iit_key_encoded_size = 0;
const char *inpath, *outpath, *password;
if (argc < 4)
{
fprintf(stderr, "Not enough arguments\n");
print_usage();
return 0;
}
inpath = argv[1];
outpath = argv[2];
password = argv[3];
iit_key_encoded_size = read_file(inpath, &iit_key_encoded);
if (iit_key_encoded_size <= 0)
{
fprintf(stderr, "Error reading input file\n");
return 0;
}
encoded_data = iit_key_encoded;
if (!d2i_IIT_key(&key, &encoded_data, iit_key_encoded_size))
{
fprintf(stderr, "Error parsing input file\n");
goto err;
}
if (key->info->oid->length != sizeof(iit_key_oid))
{
fprintf(stderr, "Error parsing input file\n");
goto err;
}
if (memcmp(key->info->oid->data, iit_key_oid, sizeof(iit_key_oid)))
{
fprintf(stderr, "Error parsing input file\n");
goto err;
}
if (ASN1_STRING_length(key->info->params->mac) != 4)
{
fprintf(stderr, "Error parsing input file\n");
goto err;
}
password_to_key(password, sk);
decrypt_data(ASN1_STRING_data(key->encrypted_key), ASN1_STRING_length(key->encrypted_key), sk, ASN1_STRING_data(key->info->params->aux));
if (check_mac(ASN1_STRING_data(key->encrypted_key), ASN1_STRING_length(key->encrypted_key), sk, ASN1_STRING_data(key->info->params->mac)))
{
fprintf(stderr, "Error parsing input file\n");
goto err;
}
encoded_data = ASN1_STRING_data(key->encrypted_key);
ENGINE_load_dstu();
if (!d2i_AutoPrivateKey(&pkey, &encoded_data, ASN1_STRING_length(key->encrypted_key)))
{
fprintf(stderr, "Error parsing input file\n");
goto err;
}
out = BIO_new_file(outpath, "wb");
if (!out)
{
fprintf(stderr, "Error writing output file\n");
goto err;
}
if (!PEM_write_bio_PrivateKey(out, pkey, EVP_get_cipherbynid(NID_dstu28147_cfb), NULL, 0, NULL, (void *)password))
{
fprintf(stderr, "Error writing output file\n");
goto err;
}
err:
if (out)
BIO_free(out);
if (pkey)
EVP_PKEY_free(pkey);
if (key)
{
memset(ASN1_STRING_data(key->encrypted_key), 0, ASN1_STRING_length(key->encrypted_key));
IIT_key_free(key);
}
if (iit_key_encoded)
free(iit_key_encoded);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment