CERT C: Rec. MSC18-C
Be careful while handling sensitive data, such as passwords, in program code
Description
Rule Definition
Be careful while handling sensitive data, such as passwords, in program code.1
Polyspace Implementation
The rule checker checks for these issues:
Constant block cipher initialization vector.
Constant cipher key.
Predictable block cipher initialization vector.
Predictable cipher key.
Sensitive heap memory not cleared before release.
Uncleared sensitive data in stack.
Unsafe standard encryption function.
Examples
Constant block cipher initialization vector
Constant block cipher initialization vector occurs when you use a constant for the initialization vector (IV) during encryption.
Using a constant IV is equivalent to not using an IV. Your encrypted data is vulnerable to dictionary attacks.
Block ciphers break your data into blocks of fixed size. Block cipher modes such as CBC (Cipher Block Chaining) protect against dictionary attacks by XOR-ing each block with the encrypted output from the previous block. To protect the first block, these modes use a random initialization vector (IV). If you use a constant IV to encrypt multiple data streams that have a common beginning, your data becomes vulnerable to dictionary attacks.
Produce a random IV by using a strong random number generator.
For a list of random number generators that are cryptographically
weak, see Vulnerable pseudo-random
number generator
.
#include <openssl/evp.h> #include <stdlib.h> #define SIZE16 16 /* Using the cryptographic routines */ int func(EVP_CIPHER_CTX *ctx, unsigned char *key){ unsigned char iv[SIZE16] = {'1', '2', '3', '4','5','6','b','8','9', '1','2','3','4','5','6','7'}; return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); //Noncompliant }
In this example, the initialization vector iv
has
constants only. The constant initialization vector makes your cipher
vulnerable to dictionary attacks.
One possible correction is to use a strong random number generator
to produce the initialization vector. The corrected code here uses
the function RAND_bytes
declared in openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 /* Using the cryptographic routines */ int func(EVP_CIPHER_CTX *ctx, unsigned char *key){ unsigned char iv[SIZE16]; RAND_bytes(iv, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Constant cipher key
Constant cipher key occurs when you use a constant for the encryption or decryption key.
If you use a constant for the encryption or decryption key, an attacker can retrieve your key easily.
You use a key to encrypt and later decrypt your data. If a key is easily retrieved, data encrypted using that key is not secure.
Produce a random key by using a strong random number generator.
For a list of random number generators that are cryptographically
weak, see Vulnerable pseudo-random
number generator
.
#include <openssl/evp.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){ unsigned char key[SIZE16] = {'1', '2', '3', '4','5','6','b','8','9', '1','2','3','4','5','6','7'}; return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); //Noncompliant }
In this example, the cipher key, key
, has
constants only. An attacker can easily retrieve a constant key.
Use a strong random number generator to produce the cipher key.
The corrected code here uses the function RAND_bytes
declared
in openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){ unsigned char key[SIZE16]; RAND_bytes(key, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Predictable block cipher initialization vector
Predictable block cipher initialization vector occurs when you use a weak random number generator for the block cipher initialization vector.
If you use a weak random number generator for the initiation vector, your data is vulnerable to dictionary attacks.
Block ciphers break your data into blocks of fixed size. Block cipher modes such as CBC (Cipher Block Chaining) protect against dictionary attacks by XOR-ing each block with the encrypted output from the previous block. To protect the first block, these modes use a random initialization vector (IV). If you use a weak random number generator for your IV, your data becomes vulnerable to dictionary attacks.
Use a strong pseudo-random number generator (PRNG) for the initialization vector. For instance, use:
OS-level PRNG such as
/dev/random
on UNIX® orCryptGenRandom()
on Windows®Application-level PRNG such as Advanced Encryption Standard (AES) in Counter (CTR) mode, HMAC-SHA1, etc.
For a list of random number generators that are cryptographically
weak, see Vulnerable pseudo-random
number generator
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *key){ unsigned char iv[SIZE16]; RAND_pseudo_bytes(iv, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); //Noncompliant }
In this example, the function RAND_pseudo_bytes
declared
in openssl/rand.h
produces the initialization vector.
The byte sequences that RAND_pseudo_bytes
generates
are not necessarily unpredictable.
Use a strong random number generator to produce the initialization
vector. The corrected code here uses the function RAND_bytes
declared
in openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *key){ unsigned char iv[SIZE16]; RAND_bytes(iv, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Predictable cipher key
Predictable cipher key occurs when you use a weak random number generator for the encryption or decryption key.
If you use a weak random number generator for the encryption or decryption key, an attacker can retrieve your key easily.
You use a key to encrypt and later decrypt your data. If a key is easily retrieved, data encrypted using that key is not secure.
Use a strong pseudo-random number generator (PRNG) for the key. For instance:
Use an OS-level PRNG such as
/dev/random
on UNIX orCryptGenRandom()
on WindowsUse an application-level PRNG such as Advanced Encryption Standard (AES) in Counter (CTR) mode, HMAC-SHA1, etc.
For a list of random number generators that are cryptographically
weak, see Vulnerable pseudo-random
number generator
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){ unsigned char key[SIZE16]; RAND_pseudo_bytes(key, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); //Noncompliant }
In this example, the function RAND_pseudo_bytes
declared
in openssl/rand.h
produces the cipher key. However,
the byte sequences that RAND_pseudo_bytes
generates
are not necessarily unpredictable.
One possible correction is to use a strong random number generator
to produce the cipher key. The corrected code here uses the function RAND_bytes
declared
in openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){ unsigned char key[SIZE16]; RAND_bytes(key, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Sensitive heap memory not cleared before release
Sensitive heap memory not cleared before
release detects dynamically allocated memory containing
sensitive data. If you do not clear the sensitive data when you free
the memory, Bug Finder raises a defect on the free
function.
If the memory zone is reallocated, an attacker can still inspect the sensitive data in the old memory zone.
Before calling free
, clear out the sensitive
data using memset
or SecureZeroMemory
.
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <pwd.h> void sensitiveheapnotcleared(const char * my_user) { struct passwd* result, pwd; long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); char* buf = (char*) malloc(1024); getpwnam_r(my_user, &pwd, buf, bufsize, &result); free(buf); //Noncompliant }
In this example, the function uses a buffer of passwords and
frees the memory before the end of the function. However, the data
in the memory is not cleared by using the free
command.
One possible correction is to write over the data to clear out
the sensitive information. This example uses memset
to
write over the data with zeros.
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <pwd.h> #include <assert.h> #define isNull(arr) for(int i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) assert(arr[i]==0) void sensitiveheapnotcleared(const char * my_user) { struct passwd* result, pwd; long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); char* buf = (char*) malloc(1024); if (buf) { getpwnam_r(my_user, &pwd, buf, bufsize, &result); memset(buf, 0, (size_t)1024); isNull(buf); free(buf); } }
Uncleared sensitive data in stack
Uncleared sensitive data in stack detects static memory containing sensitive data. If you do not clear the sensitive data from your stack before exiting the function or program, Bug Finder raises a defect on the last curly brace.
Leaving sensitive information in your stack, such as passwords or user information, allows an attacker additional access to the information after your program has ended.
Before exiting a function or program, clear out the memory zones
that contain sensitive data by using memset
or SecureZeroMemory
.
#include <unistd.h> #include <sys/types.h> #include <pwd.h> void bug_sensitivestacknotcleared(const char * my_user) { struct passwd* result, pwd; long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); char buf[1024] = ""; getpwnam_r(my_user, &pwd, buf, bufsize, &result); } //Noncompliant
In this example, a static buffer is filled with password information. The program frees the stack memory at the end of the program. However, the data is still accessible from the memory.
One possible correction is to write over the memory before exiting
the function. This example uses memset
to clear
the data from the buffer memory.
#include <unistd.h> #include <string.h> #include <sys/types.h> #include <pwd.h> #include <assert.h> #define isNull(arr) for(int i=0; i<(sizeof(arr)/sizeof(arr[0])); i++) assert(arr[i]==0) void corrected_sensitivestacknotcleared(const char * my_user) { struct passwd* result, pwd; long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); char buf[1024] = ""; getpwnam_r(my_user, &pwd, buf, bufsize, &result); memset(buf, 0, (size_t)1024); isNull(buf); }
Unsafe standard encryption function
Unsafe standard
encryption function detects use of functions with a broken
or weak cryptographic algorithm. For example, crypt
is
not reentrant and is based on the risky Data Encryption Standard (DES).
The use of a broken, weak, or nonstandard algorithm can expose sensitive information to an attacker. A determined hacker can access the protected data using various techniques.
If the weak function is nonreentrant, when you use the function in concurrent programs, there is an additional race condition risk.
Avoid functions that use these encryption algorithms. Instead, use a reentrant function that uses a stronger encryption algorithm.
Note
Some implementations of crypt
support additional,
possibly more secure, encryption algorithms.
crypt
#define _GNU_SOURCE #include <pwd.h> #include <string.h> #include <crypt.h> volatile int rd = 1; const char *salt = NULL; struct crypt_data input, output; int verif_pwd(const char *pwd, const char *cipher_pwd, int safe) { int r = 0; char *decrypted_pwd = NULL; switch(safe) { case 1: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; case 2: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; default: decrypted_pwd = crypt(pwd, cipher_pwd); //Noncompliant break; } r = (strcmp(cipher_pwd, decrypted_pwd) == 0); return r; }
In this example, crypt_r
and crypt
decrypt
a password. However, crypt
is nonreentrant and
uses the unsafe Data Encryption Standard
algorithm.
crypt_r
One possible correction is to replace crypt
with crypt_r
.
#define _GNU_SOURCE #include <pwd.h> #include <string.h> #include <crypt.h> volatile int rd = 1; const char *salt = NULL; struct crypt_data input, output; int verif_pwd(const char *pwd, const char *cipher_pwd, int safe) { int r = 0; char *decrypted_pwd = NULL; switch(safe) { case 1: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; case 2: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; default: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; } r = (strcmp(cipher_pwd, decrypted_pwd) == 0); return r; }
Check Information
Group: Rec. 48. Miscellaneous (MSC) |
Version History
Introduced in R2019a
See Also
External Websites
1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.
ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)