📄 ust.c
字号:
/* * ust.c * * C implementation of the universal security transform * * David A. McGrew * Cisco Systems, Inc. *//* * * Copyright (c) 2001-2004, 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. * */#include "ust.h"debug_module_t mod_ust = { 0, /* debugging is off by default */ "ust" /* printable module name */};err_status_tust_alloc(ust_ctx_t *ctx, /* ust context */ cipher_type_id_t c_id, /* keystream generator identifier */ int cipher_key_len, /* number of octets in cipher key */ auth_type_id_t a_id, /* auth algorithm identifier */ int auth_key_len, /* number of octets in the auth key */ int auth_tag_len, /* number of octets in the auth tag */ int replay_window_len /* bits in replay window (0 == none) */ ) { err_status_t stat; debug_print(mod_ust, "allocating context", NULL); /* check replay_window_len to see if we can support the value requested */ if (replay_window_len != 128) return err_status_bad_param; /* allocate cipher */ stat = crypto_kernel_alloc_cipher(c_id, &ctx->c, cipher_key_len); if (stat) return err_status_alloc_fail; /* allocate auth function */ stat = crypto_kernel_alloc_auth(a_id, &ctx->h, auth_key_len, auth_tag_len); if (stat) { cipher_dealloc(ctx->c); return err_status_alloc_fail; } /* allocate storage for the authentication tag */ ctx->auth_tag = (octet_t *)xalloc(auth_tag_len); if (ctx->auth_tag == NULL) { cipher_dealloc(ctx->c); auth_dealloc(ctx->h); return err_status_alloc_fail; } return err_status_ok;}err_status_tust_init(ust_ctx_t *ctx, octet_t *cipher_key, octet_t *auth_key) { err_status_t stat; v128_t zero; debug_print(mod_ust, "initializing context", NULL); /* initialize cipher */ stat = cipher_init(ctx->c, cipher_key); if (stat) return err_status_init_fail; /* initialize auth function */ if (auth_key == NULL) { octet_t *buffer; /* * we need to generate the authentication key using the UST * default method (using keystream segment number zero) */ v128_set_to_zero(&zero); stat = cipher_set_iv(ctx->c, &zero); if (stat) return stat; buffer = (octet_t *)xalloc(auth_get_key_length(ctx->h)); if (buffer == NULL) return err_status_init_fail; stat = cipher_output(ctx->c, buffer, auth_get_key_length(ctx->h)); xfree(buffer); if (stat) return stat; } stat = auth_init(ctx->h, auth_key); if (stat) return err_status_init_fail; return err_status_ok;}/* * the ust_xfm function * * ctx is the ust context, which holds the cipher and hash function * keys and parameters, as well as anti-replay information * * idx is the packet index, a 64-bit unsigned integer which * should be unique for each invocation of ust_xfm for a * given ctx * * if auth_start != NULL, then authentication is provided to the * auth_len octets of data at auth_start by computing the * authentication tag and writing it to *tag; otherwise, the * authentication tag is not computed * * if enc_start != NULL, then encryption is provided to the * enc_len octets of data at enc_start by exoring keystream * into that data; otherwise, no encryption is done * * tag points to the authentication tag; after ust_xfm returns, * it contains the tag corresonding to the data at auth_start * (if auth_start != NULL) -- note that there MUST be at least * ust_tag_len(ctx) octets of storage at *tag! */err_status_tust_xfm(ust_ctx_t *ctx, /* ust context */ xtd_seq_num_t idx, /* index */ octet_t *enc_start, /* pointer to encryption start */ int enc_len, /* number of octets to encrypt */ octet_t *auth_start, /* pointer to authentication start */ int auth_len, /* number of octets to authenticate */ octet_t *tag /* authentication tag */ ) { int stat; int prefix_len = auth_get_prefix_length(ctx->h); v128_t nonce; /* set the index to idx */ nonce.v64[0] = 0; nonce.v64[1] = idx; stat = cipher_set_iv(ctx->c, &nonce); if (stat) return err_status_cipher_fail; /* if auth_start is non-null, then put keystream into tag */ if (auth_start) { /* zeroize tag, then add in keystream */ octet_string_set_to_zero(tag, prefix_len); stat = cipher_output(ctx->c, tag, prefix_len); debug_print(mod_ust, "ust_xfm prefix: %s", octet_string_hex_string(tag, prefix_len)); if (stat) return err_status_cipher_fail; } /* if enc_start is non-null, encrypt data */ if (enc_start) { stat = cipher_encrypt(ctx->c, enc_start, &enc_len); if (stat) return err_status_cipher_fail; } /* if auth_start is non-null, authenticate message */ if (auth_start) { stat = auth_compute(ctx->h, auth_start, auth_len, tag); debug_print(mod_ust, "ust_xfm tag: %s", octet_string_hex_string(tag, prefix_len)); if (stat) return err_status_auth_fail; } return err_status_ok;}/* * the ust_inv_xfm function (ust inverse transform) * * ctx is the ust context, which holds the cipher and hash function * keys and parameters, as well as anti-replay information * * idx is the packet index, a 64-bit unsigned integer which * should be unique for each invocation of ust_xfm for a * given ctx * * if auth_start != NULL, then authentication is expected on the * auth_len octets of data at auth_start by computing the * authentication tag and comparing it to the value at *tag; * otherwise, no authentication check is performed * * if enc_start != NULL, then decryption is done to the enc_len * octets of data at enc_start by exoring keystream into that data; * otherwise, no decryption is done * * tag points to the authentication tag; if auth_start != NULL, * then *tag is expected to hold the authentication tag corresponding * to the data at *auth_start -- note that there MUST be at least * ust_tag_len(ctx) octets of readable data at *tag! */err_status_tust_inv_xfm(ust_ctx_t *ctx, /* ust context */ xtd_seq_num_t idx, /* index */ octet_t *enc_start, /* pointer to encryption start */ int enc_len, /* number of octets to encrypt */ octet_t *auth_start, /* pointer to authentication start */ int auth_len, /* number of octets to authenticate */ octet_t *tag /* authentication tag */ ) { int stat; v128_t nonce; /* set the index to idx */ nonce.v64[0] = 0; nonce.v64[1] = idx; stat = cipher_set_iv(ctx->c, &nonce); if (stat) return err_status_cipher_fail; /* * if auth_start is non-null, then put keystream into tag in ctx, * compute auth_tag and compare to tag */ if (auth_start) { /* zeroize tag, then add in keystream */ stat = cipher_output(ctx->c, ctx->auth_tag, ctx->h->out_len); debug_print(mod_ust, "ust_inv_xfm prefix: %s", octet_string_hex_string(ctx->auth_tag, ctx->h->out_len)); if (stat) return err_status_cipher_fail; /* compute hash then compare to tag value */ stat = auth_compute(ctx->h, auth_start, auth_len, ctx->auth_tag); if (stat) return err_status_auth_fail; debug_print(mod_ust, "ust_inv_xfm tag: %s", octet_string_hex_string(ctx->auth_tag, ctx->h->out_len)); debug_print(mod_ust, "tag expected: %s", octet_string_hex_string(tag, ctx->h->out_len)); if (octet_string_is_eq(ctx->auth_tag, tag, ctx->h->out_len)) { return err_status_auth_fail; } } /* if enc_start is non-null, decrypt data */ if (enc_start) { stat = cipher_encrypt(ctx->c, enc_start, &enc_len); if (stat) return err_status_cipher_fail; } return err_status_ok;}/* * ust_xfm_u16() * * implements the ust transform with 16-bit explicit seq num */err_status_tust_xfm_u16(ust_ptr_t ctx, /* pointer to ust context */ uint16_t idx, /* index */ octet_t *enc_start, /* pointer to encryption start */ int enc_len, /* number of octets to encrypt */ octet_t *auth_start, /* pointer to authentication start */ int auth_len, /* number of octets to authenticate */ octet_t *tag /* authentication tag */ ) { xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ int delta; /* delta of local pkt idx and that in hdr */ err_status_t status; /* * estimate the packet index using the start of the replay window * and the sequence number from the header */ delta = rdbx_estimate_index(&ctx->rdbx, &est, idx); status = rdbx_check(&ctx->rdbx, delta); if (status) return status; /* we've been asked to reuse an index */ rdbx_add_index(&ctx->rdbx, delta); /* now apply crypto transform */ status = ust_xfm(ctx, /* ust context */ est, /* 64-bit implicit seq num */ enc_start, /* pointer to encryption start */ enc_len, /* number of octets to encrypt */ auth_start, /* pointer to authentication start */ auth_len, /* number of octets to authenticate */ tag /* authentication tag */ ); if (status) return status; /* add index into rdbx */ rdbx_add_index(&ctx->rdbx, delta); return err_status_ok;}/* * ust_inv_xfm_u16() * * implements inverse transform with 16-bit explicit seq num */err_status_tust_inv_xfm_u16( ust_ctx_t *ctx, /* ust context */ uint16_t seq, /* 16-bit explicit seq num */ octet_t *enc_start, /* pointer to encryption start */ int enc_len, /* number of octets to encrypt */ octet_t *auth_start, /* pointer to authentication start */ int auth_len, /* number of octets to authenticate */ octet_t *tag /* authentication tag */ ) { int delta; /* delta of local pkt idx and that in hdr */ xtd_seq_num_t est; /* estimated xtd_seq_num_t */ err_status_t status; /* * estimate the packet index using the start of the replay window * and the sequence number from the header */ delta = rdbx_estimate_index(&ctx->rdbx, &est, seq); status = rdbx_check(&ctx->rdbx, delta); if (status) return status; status = ust_inv_xfm(ctx, /* ust context */ est, /* 64-bit implicit seq num */ enc_start, /* pointer to encryption start */ enc_len, /* number of octets to encrypt */ auth_start, /* pointer to authentication start */ auth_len, /* number of octets to authenticate */ tag /* authentication tag */ ); if (status) return status; /* add index into rdbx */ rdbx_add_index(&ctx->rdbx, delta); return err_status_ok;}/* * ust_get_tag_len(ctx) returns the length (in octets) of the * authentication tag for the ust context ctx. * * this function can be used to determine the storage * space required to hold a particular tag, if need be */inline unsigned int ust_get_tag_len(ust_ctx_t *ctx) { return ctx->h->out_len;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -