Main Content

CWE Rule 759

Use of a One-Way Hash without a Salt

Since R2024a

Description

Rule Description

The product uses a one-way cryptographic hash against an input that should not be reversible, such as a password, but the product does not also use a salt as part of the input.

Polyspace Implementation

The rule checker checks for Missing salt for hashing operation.

Examples

expand all

Issue

This issue occurs when you use a digest context in these functions, but you hash data into the context only once or you use a null salt in all subsequent hashing operations. A salt is random data that you use to improve the security of a hashing operation. The hashing operation takes the salt as an input to produce a more secure hashed value.

  • EVP_DigestFinal

  • EVP_DigestSignUpdate

  • EVP_DigestVerifyUpdate

  • SHA*_Final family of functions

Missing salt for hashing operation raises no defect if no information is available about the context. For instance, if the context is passed as an argument to the function that calls the hashing operation or if the context is declared outside the scope of the function. For example, no defect is raised in this code snippet.

EVP_MD_CTX ctx_global;

void foo(EVP_MD_CTX* ctx) {
//ctx passed as argument of func()
    EVP_DigestFinal(ctx, out_buf, &out_len); //no defect
}

void bar() {
// ctx_global declared outside of bar() 
    EVP_DigestFinal(&ctx_glob, out_buf, &out_len); //no defect
}

Risk

Hashing the same data without a salt results in the same hashed value. For instance, if you hash user passwords and two users have the same passwords, the hashed passwords are identical. The hashing is then vulnerable to precomputed rainbow attacks.

Fix

Provide a salt when you hash data.

Example — Data Hashed Into Context Only Once
#include <openssl/evp.h>
#include <cstring>

unsigned char* out_buf;
unsigned int out_len;

void func()
{
    const char* src = "toto";
    EVP_MD_CTX ctx;

    EVP_DigestInit(&ctx, EVP_sha256());
    EVP_DigestUpdate(&ctx, src, strlen(src));
    EVP_DigestFinal(&ctx, out_buf, &out_len); //Noncompliant
    EVP_cleanup();
}

In this example, context ctx is initialized with secure hashing algorithm SHA-256, then EVP_DigestUpdate hashes src into ctx. Because EVP_DigestUpdate is called only once, no salt can be provided to improve the security of the hashing operation. The digest value that EVP_DigestFinal retrieves is then vulnerable to precomputed rainbow attacks.

Correction — Hash Salt Into Context After Initial Data Hash

One possible correction is to hash a salt into the context ctx after the first hashing operation. The resulting digest value that EVP_DigestFinal retrieves is more secure.

#include <openssl/evp.h>
#include <openssl/rand.h>
#include <cstring>

#define BUFF_SIZE_32 32

unsigned char* out_buf;
unsigned int out_len;

void func()
{
    const char* src = "toto";
    const char* salt;

    RAND_bytes((unsigned char*)salt, BUFF_SIZE_32);
    EVP_MD_CTX ctx;

    EVP_DigestInit(&ctx, EVP_sha256());
    EVP_DigestUpdate(&ctx, src, strlen(src));
    EVP_DigestUpdate(&ctx, salt, BUFF_SIZE_32);
    EVP_DigestFinal(&ctx, out_buf, &out_len);
    EVP_cleanup();
}

Check Information

Category: Others

Version History

Introduced in R2024a