Exemple #1
0
/*
 * Packet-oriented wrapper for non-AEAD modes
 */
int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
                  const unsigned char *iv, size_t iv_len,
                  const unsigned char *input, size_t ilen,
                  unsigned char *output, size_t *olen )
{
    int ret;
    size_t finish_olen;

    if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
        return( ret );

    if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
        return( ret );

    if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
        return( ret );

    if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
        return( ret );

    *olen += finish_olen;

    return( 0 );
}
static void cipher_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
        unsigned long len)
{
    size_t outlen = 0;
    int rc = 0;
    size_t total_len = 0;

    rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen);
    if (rc != 0) {
        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption");
        return;
    }

    total_len += outlen;

    if (total_len == len) {
        return;
    }

    rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out +
            outlen, &outlen);

    if (rc != 0) {
        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption");
        return;
    }

    total_len += outlen;

    if (total_len != len) {
        SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
                outlen, len);
        return;
    }

}
static int cipher_context_update(cipher_ctx_t *ctx, uint8_t *output, int *olen,
                                 const uint8_t *input, int ilen)
{
#ifdef USE_CRYPTO_APPLECC
    cipher_cc_t *cc = &ctx->cc;
    if (cc->valid == kCCContextValid) {
        CCCryptorStatus ret;
        ret = CCCryptorUpdate(cc->cryptor, input, ilen, output,
                              ilen, (size_t *)olen);
        return (ret == kCCSuccess) ? 1 : 0;
    }
#endif
    cipher_evp_t *evp = &ctx->evp;
#if defined(USE_CRYPTO_OPENSSL)
    return EVP_CipherUpdate(evp, (uint8_t *)output, olen,
                            (const uint8_t *)input, (size_t)ilen);
#elif defined(USE_CRYPTO_POLARSSL)
    return !cipher_update(evp, (const uint8_t *)input, (size_t)ilen,
                          (uint8_t *)output, (size_t *)olen);
#elif defined(USE_CRYPTO_MBEDTLS)
    return !mbedtls_cipher_update(evp, (const uint8_t *)input, (size_t)ilen,
                                  (uint8_t *)output, (size_t *)olen);
#endif
}
Exemple #4
0
/*
 * KW-AD as defined in SP 800-38F section 6.2
 * KWP-AD as defined in SP 800-38F section 6.3
 */
int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx,
                            mbedtls_nist_kw_mode_t mode,
                            const unsigned char *input, size_t in_len,
                            unsigned char *output, size_t *out_len, size_t out_size )
{
    int ret = 0;
    size_t i, olen;
    unsigned char A[KW_SEMIBLOCK_LENGTH];
    unsigned char diff, bad_padding = 0;

    *out_len = 0;
    if( out_size < in_len - KW_SEMIBLOCK_LENGTH )
    {
        return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
    }

    if( mode == MBEDTLS_KW_MODE_KW )
    {
        /*
         * According to SP 800-38F Table 1, the ciphertext length for KW
         * must be between 3 to 2^54 semiblocks inclusive.
         */
        if( in_len < 24 ||
#if SIZE_MAX > 0x200000000000000
            in_len > 0x200000000000000 ||
#endif
            in_len % KW_SEMIBLOCK_LENGTH != 0 )
        {
            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
        }

        ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
                      A, output, out_len );
        if( ret != 0 )
            goto cleanup;

        /* Check ICV in "constant-time" */
        diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH );

        if( diff != 0 )
        {
            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
            goto cleanup;
        }

    }
    else if( mode == MBEDTLS_KW_MODE_KWP )
    {
        size_t padlen = 0;
        uint32_t Plen;
        /*
         * According to SP 800-38F Table 1, the ciphertext length for KWP
         * must be between 2 to 2^29 semiblocks inclusive.
         */
        if( in_len < KW_SEMIBLOCK_LENGTH * 2 ||
#if SIZE_MAX > 0x100000000
            in_len > 0x100000000 ||
#endif
            in_len % KW_SEMIBLOCK_LENGTH != 0 )
        {
            return(  MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
        }

        if( in_len == KW_SEMIBLOCK_LENGTH * 2 )
        {
            unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
            ret = mbedtls_cipher_update( &ctx->cipher_ctx,
                                         input, 16, outbuff, &olen );
            if( ret != 0 )
                goto cleanup;

            memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
            memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
            mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
            *out_len = KW_SEMIBLOCK_LENGTH;
        }
        else
        {
            /* in_len >=  KW_SEMIBLOCK_LENGTH * 3 */
            ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
                          A, output, out_len );
            if( ret != 0 )
                goto cleanup;
        }

        /* Check ICV in "constant-time" */
        diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 );

        if( diff != 0 )
        {
            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        }

        GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 );

        /*
         * Plen is the length of the plaintext, when the input is valid.
         * If Plen is larger than the plaintext and padding, padlen will be
         * larger than 8, because of the type wrap around.
         */
        padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
        if ( padlen > 7 )
        {
            padlen &= 7;
            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        }

        /* Check padding in "constant-time" */
        for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ )
        {
             if( i >= KW_SEMIBLOCK_LENGTH - padlen )
                 diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
             else
                 bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
        }

        if( diff != 0 )
        {
            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
        }

        if( ret != 0 )
        {
            goto cleanup;
        }
        memset( output + Plen, 0, padlen );
        *out_len = Plen;
    }
    else
    {
        ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
        goto cleanup;
    }

cleanup:
    if( ret != 0 )
    {
        memset( output, 0, *out_len );
        *out_len = 0;
    }

    mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) );
    mbedtls_platform_zeroize( &diff, sizeof( diff ) );
    mbedtls_platform_zeroize( A, sizeof( A ) );

    return( ret );
}
Exemple #5
0
/*
 * KW-AE as defined in SP 800-38F section 6.2
 * KWP-AE as defined in SP 800-38F section 6.3
 */
int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx,
                          mbedtls_nist_kw_mode_t mode,
                          const unsigned char *input, size_t in_len,
                          unsigned char *output, size_t *out_len, size_t out_size )
{
    int ret = 0;
    size_t semiblocks = 0;
    size_t s;
    size_t olen, padlen = 0;
    uint64_t t = 0;
    unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
    unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
    unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
    unsigned char *A = output;

    *out_len = 0;
    /*
     * Generate the String to work on
     */
    if( mode == MBEDTLS_KW_MODE_KW )
    {
        if( out_size < in_len + KW_SEMIBLOCK_LENGTH )
        {
            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
        }

        /*
         * According to SP 800-38F Table 1, the plaintext length for KW
         * must be between 2 to 2^54-1 semiblocks inclusive.
         */
        if( in_len < 16 ||
#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
            in_len > 0x1FFFFFFFFFFFFF8 ||
#endif
            in_len % KW_SEMIBLOCK_LENGTH != 0 )
        {
            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
        }

        memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH );
        memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len );
    }
    else
    {
        if( in_len % 8 != 0 )
        {
            padlen = ( 8 - ( in_len % 8 ) );
        }

        if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen )
        {
            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
        }

        /*
         * According to SP 800-38F Table 1, the plaintext length for KWP
         * must be between 1 and 2^32-1 octets inclusive.
         */
        if( in_len < 1
#if SIZE_MAX > 0xFFFFFFFF
            || in_len > 0xFFFFFFFF
#endif
          )
        {
            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
        }

        memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 );
        PUT_UINT32_BE( ( in_len & 0xffffffff ), output,
                       KW_SEMIBLOCK_LENGTH / 2 );

        memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len );
        memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen );
    }
    semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1;

    s = 6 * ( semiblocks - 1 );

    if( mode == MBEDTLS_KW_MODE_KWP
        && in_len <= KW_SEMIBLOCK_LENGTH )
    {
        memcpy( inbuff, output, 16 );
        ret = mbedtls_cipher_update( &ctx->cipher_ctx,
                                     inbuff, 16, output, &olen );
        if( ret != 0 )
            goto cleanup;
    }
    else
    {
        /*
         * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
         */
        if( semiblocks < MIN_SEMIBLOCKS_COUNT )
        {
            ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
            goto cleanup;
        }

        /* Calculate intermediate values */
        for( t = 1; t <= s; t++ )
        {
            memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
            memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH );

            ret = mbedtls_cipher_update( &ctx->cipher_ctx,
                                         inbuff, 16, outbuff, &olen );
            if( ret != 0 )
                goto cleanup;

            memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
            calc_a_xor_t( A, t );

            memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
            R2 += KW_SEMIBLOCK_LENGTH;
            if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) )
                R2 = output + KW_SEMIBLOCK_LENGTH;
        }
    }

    *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;

cleanup:

    if( ret != 0)
    {
        memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH );
    }
    mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 );
    mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 );

    return( ret );
}