Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cipher.c   Sprache: C

 
/*
 * cipher.c
 *
 * cipher meta-functions
 *
 * David A. McGrew
 * Cisco Systems, Inc.
 *
 */


/*
 *
 * Copyright (c) 2001-2017 Cisco Systems, Inc.
 * 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.
 *
 *   Neither the name of the Cisco Systems, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * 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 HOLDERS 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.
 *
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "cipher.h"
#include "cipher_priv.h"
#include "crypto_types.h"
#include "err.h"   /* for srtp_debug */
#include "alloc.h" /* for crypto_alloc(), crypto_free()  */

srtp_debug_module_t srtp_mod_cipher = {
    0,       /* debugging is off by default */
    "cipher" /* printable module name       */
};

srtp_err_status_t srtp_cipher_type_alloc(const srtp_cipher_type_t *ct,
                                         srtp_cipher_t **c,
                                         int key_len,
                                         int tlen)
{
    if (!ct || !ct->alloc) {
        return (srtp_err_status_bad_param);
    }
    return ((ct)->alloc((c), (key_len), (tlen)));
}

srtp_err_status_t srtp_cipher_dealloc(srtp_cipher_t *c)
{
    if (!c || !c->type) {
        return (srtp_err_status_bad_param);
    }
    return (((c)->type)->dealloc(c));
}

srtp_err_status_t srtp_cipher_init(srtp_cipher_t *c, const uint8_t *key)
{
    if (!c || !c->type || !c->state) {
        return (srtp_err_status_bad_param);
    }
    return (((c)->type)->init(((c)->state), (key)));
}

srtp_err_status_t srtp_cipher_set_iv(srtp_cipher_t *c,
                                     uint8_t *iv,
                                     int direction)
{
    if (!c || !c->type || !c->state) {
        return (srtp_err_status_bad_param);
    }

    return (((c)->type)->set_iv(((c)->state), iv, direction));
}

srtp_err_status_t srtp_cipher_output(srtp_cipher_t *c,
                                     uint8_t *buffer,
                                     uint32_t *num_octets_to_output)
{
    /* zeroize the buffer */
    octet_string_set_to_zero(buffer, *num_octets_to_output);

    /* exor keystream into buffer */
    return (((c)->type)->encrypt(((c)->state), buffer, num_octets_to_output));
}

srtp_err_status_t srtp_cipher_encrypt(srtp_cipher_t *c,
                                      uint8_t *buffer,
                                      uint32_t *num_octets_to_output)
{
    if (!c || !c->type || !c->state) {
        return (srtp_err_status_bad_param);
    }

    return (((c)->type)->encrypt(((c)->state), buffer, num_octets_to_output));
}

srtp_err_status_t srtp_cipher_decrypt(srtp_cipher_t *c,
                                      uint8_t *buffer,
                                      uint32_t *num_octets_to_output)
{
    if (!c || !c->type || !c->state) {
        return (srtp_err_status_bad_param);
    }

    return (((c)->type)->decrypt(((c)->state), buffer, num_octets_to_output));
}

srtp_err_status_t srtp_cipher_get_tag(srtp_cipher_t *c,
                                      uint8_t *buffer,
                                      uint32_t *tag_len)
{
    if (!c || !c->type || !c->state) {
        return (srtp_err_status_bad_param);
    }
    if (!((c)->type)->get_tag) {
        return (srtp_err_status_no_such_op);
    }

    return (((c)->type)->get_tag(((c)->state), buffer, tag_len));
}

srtp_err_status_t srtp_cipher_set_aad(srtp_cipher_t *c,
                                      const uint8_t *aad,
                                      uint32_t aad_len)
{
    if (!c || !c->type || !c->state) {
        return (srtp_err_status_bad_param);
    }
    if (!((c)->type)->set_aad) {
        return (srtp_err_status_no_such_op);
    }

    return (((c)->type)->set_aad(((c)->state), aad, aad_len));
}

/* some bookkeeping functions */

int srtp_cipher_get_key_length(const srtp_cipher_t *c)
{
    return c->key_len;
}

/*
 * A trivial platform independent random source.
 * For use in test only.
 */

void srtp_cipher_rand_for_tests(void *dest, uint32_t len)
{
    /* Generic C-library (rand()) version */
    /* This is a random source of last resort */
    uint8_t *dst = (uint8_t *)dest;
    while (len) {
        int val = rand();
        /* rand() returns 0-32767 (ugh) */
        /* Is this a good enough way to get random bytes?
           It is if it passes FIPS-140... */

        *dst++ = val & 0xff;
        len--;
    }
}

/*
 * A trivial platform independent 32 bit random number.
 * For use in test only.
 */

uint32_t srtp_cipher_rand_u32_for_tests(void)
{
    uint32_t r;
    srtp_cipher_rand_for_tests(&r, sizeof(r));
    return r;
}

#define SELF_TEST_BUF_OCTETS 128
#define NUM_RAND_TESTS 128
#define MAX_KEY_LEN 64
/*
 * srtp_cipher_type_test(ct, test_data) tests a cipher of type ct against
 * test cases provided in a list test_data of values of key, salt, iv,
 * plaintext, and ciphertext that is known to be good
 */

srtp_err_status_t srtp_cipher_type_test(
    const srtp_cipher_type_t *ct,
    const srtp_cipher_test_case_t *test_data)
{
    const srtp_cipher_test_case_t *test_case = test_data;
    srtp_cipher_t *c;
    srtp_err_status_t status;
    uint8_t buffer[SELF_TEST_BUF_OCTETS];
    uint8_t buffer2[SELF_TEST_BUF_OCTETS];
    uint32_t tag_len;
    unsigned int len;
    int i, j, case_num = 0;
    unsigned k = 0;

    debug_print(srtp_mod_cipher, "running self-test for cipher %s",
                ct->description);

    /*
     * check to make sure that we have at least one test case, and
     * return an error if we don't - we need to be paranoid here
     */

    if (test_case == NULL) {
        return srtp_err_status_cant_check;
    }

    /*
     * loop over all test cases, perform known-answer tests of both the
     * encryption and decryption functions
     */

    while (test_case != NULL) {
        /* allocate cipher */
        status = srtp_cipher_type_alloc(ct, &c, test_case->key_length_octets,
                                        test_case->tag_length_octets);
        if (status) {
            return status;
        }

        /*
         * test the encrypt function
         */

        debug_print0(srtp_mod_cipher, "testing encryption");

        /* initialize cipher */
        status = srtp_cipher_init(c, test_case->key);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        /* copy plaintext into test buffer */
        if (test_case->ciphertext_length_octets > SELF_TEST_BUF_OCTETS) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_bad_param;
        }
        for (k = 0; k < test_case->plaintext_length_octets; k++) {
            buffer[k] = test_case->plaintext[k];
        }

        debug_print(srtp_mod_cipher, "plaintext: %s",
                    srtp_octet_string_hex_string(
                        buffer, test_case->plaintext_length_octets));

        /* set the initialization vector */
        status = srtp_cipher_set_iv(c, (uint8_t *)test_case->idx,
                                    srtp_direction_encrypt);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        if (c->algorithm == SRTP_AES_GCM_128 ||
            c->algorithm == SRTP_AES_GCM_256) {
            debug_print(srtp_mod_cipher, "IV: %s",
                        srtp_octet_string_hex_string(test_case->idx, 12));

            /*
             * Set the AAD
             */

            status = srtp_cipher_set_aad(c, test_case->aad,
                                         test_case->aad_length_octets);
            if (status) {
                srtp_cipher_dealloc(c);
                return status;
            }
            debug_print(srtp_mod_cipher, "AAD: %s",
                        srtp_octet_string_hex_string(
                            test_case->aad, test_case->aad_length_octets));
        }

        /* encrypt */
        len = test_case->plaintext_length_octets;
        status = srtp_cipher_encrypt(c, buffer, &len);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        if (c->algorithm == SRTP_AES_GCM_128 ||
            c->algorithm == SRTP_AES_GCM_256) {
            /*
             * Get the GCM tag
             */

            status = srtp_cipher_get_tag(c, buffer + len, &tag_len);
            if (status) {
                srtp_cipher_dealloc(c);
                return status;
            }
            len += tag_len;
        }

        debug_print(srtp_mod_cipher, "ciphertext: %s",
                    srtp_octet_string_hex_string(
                        buffer, test_case->ciphertext_length_octets));

        /* compare the resulting ciphertext with that in the test case */
        if (len != test_case->ciphertext_length_octets) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_algo_fail;
        }
        status = srtp_err_status_ok;
        for (k = 0; k < test_case->ciphertext_length_octets; k++) {
            if (buffer[k] != test_case->ciphertext[k]) {
                status = srtp_err_status_algo_fail;
                debug_print(srtp_mod_cipher, "test case %d failed", case_num);
                debug_print(srtp_mod_cipher, "(failure at byte %u)", k);
                break;
            }
        }
        if (status) {
            debug_print(srtp_mod_cipher, "c computed: %s",
                        srtp_octet_string_hex_string(
                            buffer, 2 * test_case->plaintext_length_octets));
            debug_print(srtp_mod_cipher, "c expected: %s",
                        srtp_octet_string_hex_string(
                            test_case->ciphertext,
                            2 * test_case->plaintext_length_octets));

            srtp_cipher_dealloc(c);
            return srtp_err_status_algo_fail;
        }

        /*
         * test the decrypt function
         */

        debug_print0(srtp_mod_cipher, "testing decryption");

        /* re-initialize cipher for decryption */
        status = srtp_cipher_init(c, test_case->key);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        /* copy ciphertext into test buffer */
        if (test_case->ciphertext_length_octets > SELF_TEST_BUF_OCTETS) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_bad_param;
        }
        for (k = 0; k < test_case->ciphertext_length_octets; k++) {
            buffer[k] = test_case->ciphertext[k];
        }

        debug_print(srtp_mod_cipher, "ciphertext: %s",
                    srtp_octet_string_hex_string(
                        buffer, test_case->plaintext_length_octets));

        /* set the initialization vector */
        status = srtp_cipher_set_iv(c, (uint8_t *)test_case->idx,
                                    srtp_direction_decrypt);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        if (c->algorithm == SRTP_AES_GCM_128 ||
            c->algorithm == SRTP_AES_GCM_256) {
            /*
             * Set the AAD
             */

            status = srtp_cipher_set_aad(c, test_case->aad,
                                         test_case->aad_length_octets);
            if (status) {
                srtp_cipher_dealloc(c);
                return status;
            }
            debug_print(srtp_mod_cipher, "AAD: %s",
                        srtp_octet_string_hex_string(
                            test_case->aad, test_case->aad_length_octets));
        }

        /* decrypt */
        len = test_case->ciphertext_length_octets;
        status = srtp_cipher_decrypt(c, buffer, &len);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        debug_print(srtp_mod_cipher, "plaintext: %s",
                    srtp_octet_string_hex_string(
                        buffer, test_case->plaintext_length_octets));

        /* compare the resulting plaintext with that in the test case */
        if (len != test_case->plaintext_length_octets) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_algo_fail;
        }
        status = srtp_err_status_ok;
        for (k = 0; k < test_case->plaintext_length_octets; k++) {
            if (buffer[k] != test_case->plaintext[k]) {
                status = srtp_err_status_algo_fail;
                debug_print(srtp_mod_cipher, "test case %d failed", case_num);
                debug_print(srtp_mod_cipher, "(failure at byte %u)", k);
            }
        }
        if (status) {
            debug_print(srtp_mod_cipher, "p computed: %s",
                        srtp_octet_string_hex_string(
                            buffer, 2 * test_case->plaintext_length_octets));
            debug_print(srtp_mod_cipher, "p expected: %s",
                        srtp_octet_string_hex_string(
                            test_case->plaintext,
                            2 * test_case->plaintext_length_octets));

            srtp_cipher_dealloc(c);
            return srtp_err_status_algo_fail;
        }

        /* deallocate the cipher */
        status = srtp_cipher_dealloc(c);
        if (status) {
            return status;
        }

        /*
         * the cipher passed the test case, so move on to the next test
         * case in the list; if NULL, we'l proceed to the next test
         */

        test_case = test_case->next_test_case;
        ++case_num;
    }

    /* now run some random invertibility tests */

    /* allocate cipher, using paramaters from the first test case */
    test_case = test_data;
    status = srtp_cipher_type_alloc(ct, &c, test_case->key_length_octets,
                                    test_case->tag_length_octets);
    if (status) {
        return status;
    }

    for (j = 0; j < NUM_RAND_TESTS; j++) {
        unsigned int length;
        unsigned int plaintext_len;
        uint8_t key[MAX_KEY_LEN];
        uint8_t iv[MAX_KEY_LEN];

        /* choose a length at random (leaving room for IV and padding) */
        length = srtp_cipher_rand_u32_for_tests() % (SELF_TEST_BUF_OCTETS - 64);
        debug_print(srtp_mod_cipher, "random plaintext length %d\n", length);
        srtp_cipher_rand_for_tests(buffer, length);

        debug_print(srtp_mod_cipher, "plaintext: %s",
                    srtp_octet_string_hex_string(buffer, length));

        /* copy plaintext into second buffer */
        for (i = 0; (unsigned int)i < length; i++) {
            buffer2[i] = buffer[i];
        }

        /* choose a key at random */
        if (test_case->key_length_octets > MAX_KEY_LEN) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_cant_check;
        }
        srtp_cipher_rand_for_tests(key, test_case->key_length_octets);

        /* chose a random initialization vector */
        srtp_cipher_rand_for_tests(iv, MAX_KEY_LEN);

        /* initialize cipher */
        status = srtp_cipher_init(c, key);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        /* set initialization vector */
        status = srtp_cipher_set_iv(c, (uint8_t *)test_case->idx,
                                    srtp_direction_encrypt);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        if (c->algorithm == SRTP_AES_GCM_128 ||
            c->algorithm == SRTP_AES_GCM_256) {
            /*
             * Set the AAD
             */

            status = srtp_cipher_set_aad(c, test_case->aad,
                                         test_case->aad_length_octets);
            if (status) {
                srtp_cipher_dealloc(c);
                return status;
            }
            debug_print(srtp_mod_cipher, "AAD: %s",
                        srtp_octet_string_hex_string(
                            test_case->aad, test_case->aad_length_octets));
        }

        /* encrypt buffer with cipher */
        plaintext_len = length;
        status = srtp_cipher_encrypt(c, buffer, &length);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }
        if (c->algorithm == SRTP_AES_GCM_128 ||
            c->algorithm == SRTP_AES_GCM_256) {
            /*
             * Get the GCM tag
             */

            status = srtp_cipher_get_tag(c, buffer + length, &tag_len);
            if (status) {
                srtp_cipher_dealloc(c);
                return status;
            }
            length += tag_len;
        }
        debug_print(srtp_mod_cipher, "ciphertext: %s",
                    srtp_octet_string_hex_string(buffer, length));

        /*
         * re-initialize cipher for decryption, re-set the iv, then
         * decrypt the ciphertext
         */

        status = srtp_cipher_init(c, key);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }
        status = srtp_cipher_set_iv(c, (uint8_t *)test_case->idx,
                                    srtp_direction_decrypt);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }
        if (c->algorithm == SRTP_AES_GCM_128 ||
            c->algorithm == SRTP_AES_GCM_256) {
            /*
             * Set the AAD
             */

            status = srtp_cipher_set_aad(c, test_case->aad,
                                         test_case->aad_length_octets);
            if (status) {
                srtp_cipher_dealloc(c);
                return status;
            }
            debug_print(srtp_mod_cipher, "AAD: %s",
                        srtp_octet_string_hex_string(
                            test_case->aad, test_case->aad_length_octets));
        }
        status = srtp_cipher_decrypt(c, buffer, &length);
        if (status) {
            srtp_cipher_dealloc(c);
            return status;
        }

        debug_print(srtp_mod_cipher, "plaintext[2]: %s",
                    srtp_octet_string_hex_string(buffer, length));

        /* compare the resulting plaintext with the original one */
        if (length != plaintext_len) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_algo_fail;
        }
        status = srtp_err_status_ok;
        for (k = 0; k < plaintext_len; k++) {
            if (buffer[k] != buffer2[k]) {
                status = srtp_err_status_algo_fail;
                debug_print(srtp_mod_cipher, "random test case %d failed",
                            case_num);
                debug_print(srtp_mod_cipher, "(failure at byte %u)", k);
            }
        }
        if (status) {
            srtp_cipher_dealloc(c);
            return srtp_err_status_algo_fail;
        }
    }

    status = srtp_cipher_dealloc(c);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

/*
 * srtp_cipher_type_self_test(ct) performs srtp_cipher_type_test on ct's
 * internal list of test data.
 */

srtp_err_status_t srtp_cipher_type_self_test(const srtp_cipher_type_t *ct)
{
    return srtp_cipher_type_test(ct, ct->test_data);
}

/*
 * cipher_bits_per_second(c, l, t) computes (an estimate of) the
 * number of bits that a cipher implementation can encrypt in a second
 *
 * c is a cipher (which MUST be allocated and initialized already), l
 * is the length in octets of the test data to be encrypted, and t is
 * the number of trials
 *
 * if an error is encountered, the value 0 is returned
 */

uint64_t srtp_cipher_bits_per_second(srtp_cipher_t *c,
                                     int octets_in_buffer,
                                     int num_trials)
{
    int i;
    v128_t nonce;
    clock_t timer;
    unsigned char *enc_buf;
    unsigned int len = octets_in_buffer;

    enc_buf = (unsigned char *)srtp_crypto_alloc(octets_in_buffer);
    if (enc_buf == NULL) {
        return 0; /* indicate bad parameters by returning null */
    }
    /* time repeated trials */
    v128_set_to_zero(&nonce);
    timer = clock();
    for (i = 0; i < num_trials; i++, nonce.v32[3] = i) {
        if (srtp_cipher_set_iv(c, (uint8_t *)&nonce, srtp_direction_encrypt) !=
            srtp_err_status_ok) {
            srtp_crypto_free(enc_buf);
            return 0;
        }
        if (srtp_cipher_encrypt(c, enc_buf, &len) != srtp_err_status_ok) {
            srtp_crypto_free(enc_buf);
            return 0;
        }
    }
    timer = clock() - timer;

    srtp_crypto_free(enc_buf);

    if (timer == 0) {
        /* Too fast! */
        return 0;
    }

    return (uint64_t)CLOCKS_PER_SEC * num_trials * 8 * octets_in_buffer / timer;
}

Messung V0.5
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.33 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge