summaryrefslogtreecommitdiffstats
path: root/ssl/s3_cbc.c
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2013-02-08 16:59:26 +0100
committerAndy Polyakov <appro@openssl.org>2013-02-08 17:01:55 +0100
commitff58eaa4b645a38f3a226cf566d969fffa64ef94 (patch)
tree89cd57bf0150cc54b5e12034a210696dbbf3a844 /ssl/s3_cbc.c
parent76c61a5d1adb92388f39e585e4af860a20feb9bb (diff)
s3_cbc.c: get rid of expensive divisions [from master].
(cherry picked from commit e9baceab5a385e570706ca98dec768b2d89d1ac6)
Diffstat (limited to 'ssl/s3_cbc.c')
-rw-r--r--ssl/s3_cbc.c35
1 files changed, 21 insertions, 14 deletions
diff --git a/ssl/s3_cbc.c b/ssl/s3_cbc.c
index 8dfc11e713..d5d00f539b 100644
--- a/ssl/s3_cbc.c
+++ b/ssl/s3_cbc.c
@@ -76,6 +76,13 @@
#define DUPLICATE_MSB_TO_ALL(x) ( (unsigned)( (int)(x) >> (sizeof(int)*8-1) ) )
#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x)))
+/* constant_time_lt returns 0xff if a<b and 0x00 otherwise. */
+static unsigned constant_time_lt(unsigned a, unsigned b)
+ {
+ a -= b;
+ return DUPLICATE_MSB_TO_ALL(a);
+ }
+
/* constant_time_ge returns 0xff if a>=b and 0x00 otherwise. */
static unsigned constant_time_ge(unsigned a, unsigned b)
{
@@ -84,7 +91,7 @@ static unsigned constant_time_ge(unsigned a, unsigned b)
}
/* constant_time_eq_8 returns 0xff if a==b and 0x00 otherwise. */
-static unsigned char constant_time_eq_8(unsigned char a, unsigned char b)
+static unsigned char constant_time_eq_8(unsigned a, unsigned b)
{
unsigned c = a ^ b;
c--;
@@ -281,16 +288,13 @@ void ssl3_cbc_copy_mac(unsigned char* out,
rotate_offset = (div_spoiler + mac_start - scan_start) % md_size;
memset(rotated_mac, 0, md_size);
- for (i = scan_start; i < orig_len;)
+ for (i = scan_start, j = 0; i < orig_len; i++)
{
- for (j = 0; j < md_size && i < orig_len; i++, j++)
- {
- unsigned char mac_started = constant_time_ge(i, mac_start);
- unsigned char mac_ended = constant_time_ge(i, mac_end);
- unsigned char b = 0;
- b = rec->data[i];
- rotated_mac[j] |= b & mac_started & ~mac_ended;
- }
+ unsigned char mac_started = constant_time_ge(i, mac_start);
+ unsigned char mac_ended = constant_time_ge(i, mac_end);
+ unsigned char b = rec->data[i];
+ rotated_mac[j++] |= b & mac_started & ~mac_ended;
+ j &= constant_time_lt(j,md_size);
}
/* Now rotate the MAC */
@@ -298,16 +302,19 @@ void ssl3_cbc_copy_mac(unsigned char* out,
j = 0;
for (i = 0; i < md_size; i++)
{
- unsigned char offset = (div_spoiler + rotate_offset + i) % md_size;
- out[j++] = rotated_mac[offset];
+ out[j++] = rotated_mac[rotate_offset++];
+ rotate_offset &= constant_time_lt(rotate_offset,md_size);
}
#else
memset(out, 0, md_size);
+ rotate_offset = md_size - rotate_offset;
+ rotate_offset &= constant_time_lt(rotate_offset,md_size);
for (i = 0; i < md_size; i++)
{
- unsigned char offset = (div_spoiler + md_size - rotate_offset + i) % md_size;
for (j = 0; j < md_size; j++)
- out[j] |= rotated_mac[i] & constant_time_eq_8(j, offset);
+ out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset);
+ rotate_offset++;
+ rotate_offset &= constant_time_lt(rotate_offset,md_size);
}
#endif
}
='n242' href='#n242'>242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
/*
 * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

/*
 * DES low level APIs are deprecated for public use, but still ok for internal
 * use.  We access the DES_set_odd_parity(3) function here.
 */
#include "internal/deprecated.h"

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include <openssl/core_names.h>
#include <openssl/des.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>

#include "internal/cryptlib.h"
#include "crypto/evp.h"
#include "internal/numbers.h"
#include "prov/implementations.h"
#include "prov/provider_ctx.h"
#include "prov/provider_util.h"
#include "prov/providercommon.h"
#include "prov/providercommonerr.h"

/* KRB5 KDF defined in RFC 3961, Section 5.1 */

static OSSL_FUNC_kdf_newctx_fn krb5kdf_new;
static OSSL_FUNC_kdf_freectx_fn krb5kdf_free;
static OSSL_FUNC_kdf_reset_fn krb5kdf_reset;
static OSSL_FUNC_kdf_derive_fn krb5kdf_derive;
static OSSL_FUNC_kdf_settable_ctx_params_fn krb5kdf_settable_ctx_params;
static OSSL_FUNC_kdf_set_ctx_params_fn krb5kdf_set_ctx_params;
static OSSL_FUNC_kdf_gettable_ctx_params_fn krb5kdf_gettable_ctx_params;
static OSSL_FUNC_kdf_get_ctx_params_fn krb5kdf_get_ctx_params;

static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine,
                   const unsigned char *key, size_t key_len,
                   const unsigned char *constant, size_t constant_len,
                   unsigned char *okey, size_t okey_len);

typedef struct {
    void *provctx;
    PROV_CIPHER cipher;
    unsigned char *key;
    size_t key_len;
    unsigned char *constant;
    size_t constant_len;
} KRB5KDF_CTX;

static void *krb5kdf_new(void *provctx)
{
    KRB5KDF_CTX *ctx;

    if (!ossl_prov_is_running())
        return NULL;

    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
        return NULL;
    }
    ctx->provctx = provctx;
    return ctx;
}

static void krb5kdf_free(void *vctx)
{
    KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;

    if (ctx != NULL) {
        krb5kdf_reset(ctx);
        OPENSSL_free(ctx);
    }
}

static void krb5kdf_reset(void *vctx)
{
    KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
    void *provctx = ctx->provctx;

    ossl_prov_cipher_reset(&ctx->cipher);
    OPENSSL_clear_free(ctx->key, ctx->key_len);
    OPENSSL_clear_free(ctx->constant, ctx->constant_len);
    memset(ctx, 0, sizeof(*ctx));
    ctx->provctx = provctx;
}

static int krb5kdf_set_membuf(unsigned char **dst, size_t *dst_len,
                              const OSSL_PARAM *p)
{
    OPENSSL_clear_free(*dst, *dst_len);
    *dst = NULL;
    return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
}

static int krb5kdf_derive(void *vctx, unsigned char *key,
                              size_t keylen)
{
    KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
    const EVP_CIPHER *cipher;
    ENGINE *engine;

    if (!ossl_prov_is_running())
        return 0;

    cipher = ossl_prov_cipher_cipher(&ctx->cipher);
    if (cipher == NULL) {
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER);
        return 0;
    }
    if (ctx->key == NULL) {
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
        return 0;
    }
    if (ctx->constant == NULL) {
        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CONSTANT);
        return 0;
    }
    engine = ossl_prov_cipher_engine(&ctx->cipher);
    return KRB5KDF(cipher, engine, ctx->key, ctx->key_len,
                   ctx->constant, ctx->constant_len,
                   key, keylen);
}

static int krb5kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
{
    const OSSL_PARAM *p;
    KRB5KDF_CTX *ctx = vctx;
    OSSL_LIB_CTX *provctx = PROV_LIBCTX_OF(ctx->provctx);

    if (!ossl_prov_cipher_load_from_params(&ctx->cipher, params, provctx))
        return 0;

    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
        if (!krb5kdf_set_membuf(&ctx->key, &ctx->key_len, p))
            return 0;

    if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CONSTANT))
        != NULL)
        if (!krb5kdf_set_membuf(&ctx->constant, &ctx->constant_len, p))
            return 0;

    return 1;
}

static const OSSL_PARAM *krb5kdf_settable_ctx_params(ossl_unused void *provctx)
{
    static const OSSL_PARAM known_settable_ctx_params[] = {
        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
        OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0),
        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
        OSSL_PARAM_octet_string(OSSL_KDF_PARAM_CONSTANT, NULL, 0),
        OSSL_PARAM_END
    };
    return known_settable_ctx_params;
}

static int krb5kdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
{
    KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
    const EVP_CIPHER *cipher;
    size_t len;
    OSSL_PARAM *p;

    cipher = ossl_prov_cipher_cipher(&ctx->cipher);
    if (cipher)
        len = EVP_CIPHER_key_length(cipher);
    else
        len = EVP_MAX_KEY_LENGTH;

    if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
        return OSSL_PARAM_set_size_t(p, len);
    return -2;
}

static const OSSL_PARAM *krb5kdf_gettable_ctx_params(ossl_unused void *provctx)
{
    static const OSSL_PARAM known_gettable_ctx_params[] = {
        OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
        OSSL_PARAM_END
    };
    return known_gettable_ctx_params;
}

const OSSL_DISPATCH ossl_kdf_krb5kdf_functions[] = {
    { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))krb5kdf_new },
    { OSSL_FUNC_KDF_FREECTX, (void(*)(void))krb5kdf_free },
    { OSSL_FUNC_KDF_RESET, (void(*)(void))krb5kdf_reset },
    { OSSL_FUNC_KDF_DERIVE, (void(*)(void))krb5kdf_derive },
    { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
      (void(*)(void))krb5kdf_settable_ctx_params },
    { OSSL_FUNC_KDF_SET_CTX_PARAMS,
      (void(*)(void))krb5kdf_set_ctx_params },
    { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
      (void(*)(void))krb5kdf_gettable_ctx_params },
    { OSSL_FUNC_KDF_GET_CTX_PARAMS,
      (void(*)(void))krb5kdf_get_ctx_params },
    { 0, NULL }
};

#ifndef OPENSSL_NO_DES
/*
 * DES3 is a special case, it requires a random-to-key function and its
 * input truncated to 21 bytes of the 24 produced by the cipher.
 * See RFC3961 6.3.1
 */
static int fixup_des3_key(unsigned char *key)
{
    unsigned char *cblock;
    int i, j;

    for (i = 2; i >= 0; i--) {
        cblock = &key[i * 8];
        memmove(cblock, &key[i * 7], 7);
        cblock[7] = 0;
        for