Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto: deduplicate cipher initialization code #23011

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 55 additions & 75 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2546,6 +2546,12 @@ int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
return 1;
}

static bool IsSupportedAuthenticatedMode(int mode) {
return mode == EVP_CIPH_CCM_MODE ||
mode == EVP_CIPH_GCM_MODE ||
mode == EVP_CIPH_OCB_MODE;
}

void CipherBase::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

Expand All @@ -2572,6 +2578,43 @@ void CipherBase::New(const FunctionCallbackInfo<Value>& args) {
new CipherBase(env, args.This(), kind);
}

void CipherBase::CommonInit(const char* cipher_type,
const EVP_CIPHER* cipher,
const unsigned char* key,
int key_len,
const unsigned char* iv,
int iv_len,
unsigned int auth_tag_len) {
CHECK(!ctx_);
ctx_.reset(EVP_CIPHER_CTX_new());

const int mode = EVP_CIPHER_mode(cipher);
if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);

const bool encrypt = (kind_ == kCipher);
if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr,
nullptr, nullptr, encrypt)) {
return ThrowCryptoError(env(), ERR_get_error(),
"Failed to initialize cipher");
}

if (IsSupportedAuthenticatedMode(mode)) {
CHECK_GE(iv_len, 0);
if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len))
return;
}

if (!EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)) {
ctx_.reset();
return env()->ThrowError("Invalid key length");
}

if (1 != EVP_CipherInit_ex(ctx_.get(), nullptr, nullptr, key, iv, encrypt)) {
return ThrowCryptoError(env(), ERR_get_error(),
"Failed to initialize cipher");
}
}

void CipherBase::Init(const char* cipher_type,
const char* key_buf,
Expand All @@ -2587,7 +2630,6 @@ void CipherBase::Init(const char* cipher_type,
}
#endif // NODE_FIPS_MODE

CHECK(!ctx_);
const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type);
if (cipher == nullptr)
return env()->ThrowError("Unknown cipher");
Expand All @@ -2605,45 +2647,19 @@ void CipherBase::Init(const char* cipher_type,
iv);
CHECK_NE(key_len, 0);

ctx_.reset(EVP_CIPHER_CTX_new());

const int mode = EVP_CIPHER_mode(cipher);
if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);

const bool encrypt = (kind_ == kCipher);
if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr,
nullptr, nullptr, encrypt)) {
return ThrowCryptoError(env(), ERR_get_error(),
"Failed to initialize cipher");
}

if (encrypt && (mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_GCM_MODE ||
mode == EVP_CIPH_CCM_MODE)) {
if (kind_ == kCipher && (mode == EVP_CIPH_CTR_MODE ||
mode == EVP_CIPH_GCM_MODE ||
mode == EVP_CIPH_CCM_MODE)) {
// Ignore the return value (i.e. possible exception) because we are
// not calling back into JS anyway.
ProcessEmitWarning(env(),
"Use Cipheriv for counter mode of %s",
cipher_type);
}

if (IsAuthenticatedMode()) {
if (!InitAuthenticated(cipher_type, EVP_CIPHER_iv_length(cipher),
auth_tag_len))
return;
}

CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len));

if (1 != EVP_CipherInit_ex(ctx_.get(),
nullptr,
nullptr,
reinterpret_cast<unsigned char*>(key),
reinterpret_cast<unsigned char*>(iv),
encrypt)) {
return ThrowCryptoError(env(), ERR_get_error(),
"Failed to initialize cipher");
}
this->CommonInit(cipher_type, cipher, key, key_len, iv,
EVP_CIPHER_iv_length(cipher), auth_tag_len);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this-> is redundant, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can remove it.

}


Expand All @@ -2670,16 +2686,10 @@ void CipherBase::Init(const FunctionCallbackInfo<Value>& args) {
cipher->Init(*cipher_type, key_buf, key_buf_len, auth_tag_len);
}

static bool IsSupportedAuthenticatedMode(int mode) {
return mode == EVP_CIPH_CCM_MODE ||
mode == EVP_CIPH_GCM_MODE ||
mode == EVP_CIPH_OCB_MODE;
}

void CipherBase::InitIv(const char* cipher_type,
const char* key,
const unsigned char* key,
int key_len,
const char* iv,
const unsigned char* iv,
int iv_len,
unsigned int auth_tag_len) {
HandleScope scope(env()->isolate());
Expand Down Expand Up @@ -2707,38 +2717,7 @@ void CipherBase::InitIv(const char* cipher_type,
return env()->ThrowError("Invalid IV length");
}

ctx_.reset(EVP_CIPHER_CTX_new());

if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);

const bool encrypt = (kind_ == kCipher);
if (1 != EVP_CipherInit_ex(ctx_.get(), cipher, nullptr,
nullptr, nullptr, encrypt)) {
return ThrowCryptoError(env(), ERR_get_error(),
"Failed to initialize cipher");
}

if (is_authenticated_mode) {
CHECK(has_iv);
if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len))
return;
}

if (!EVP_CIPHER_CTX_set_key_length(ctx_.get(), key_len)) {
ctx_.reset();
return env()->ThrowError("Invalid key length");
}

if (1 != EVP_CipherInit_ex(ctx_.get(),
nullptr,
nullptr,
reinterpret_cast<const unsigned char*>(key),
reinterpret_cast<const unsigned char*>(iv),
encrypt)) {
return ThrowCryptoError(env(), ERR_get_error(),
"Failed to initialize cipher");
}
this->CommonInit(cipher_type, cipher, key, key_len, iv, iv_len, auth_tag_len);
}


Expand All @@ -2751,14 +2730,15 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {

const node::Utf8Value cipher_type(env->isolate(), args[0]);
ssize_t key_len = Buffer::Length(args[1]);
const char* key_buf = Buffer::Data(args[1]);
const unsigned char* key_buf = reinterpret_cast<unsigned char*>(
Buffer::Data(args[1]));
ssize_t iv_len;
const char* iv_buf;
const unsigned char* iv_buf;
if (args[2]->IsNull()) {
iv_buf = nullptr;
iv_len = -1;
} else {
iv_buf = Buffer::Data(args[2]);
iv_buf = reinterpret_cast<unsigned char*>(Buffer::Data(args[2]));
iv_len = Buffer::Length(args[2]);
}

Expand Down
11 changes: 9 additions & 2 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,14 +370,21 @@ class CipherBase : public BaseObject {
};
static const unsigned kNoAuthTagLength = static_cast<unsigned>(-1);

void CommonInit(const char* cipher_type,
const EVP_CIPHER* cipher,
const unsigned char* key,
int key_len,
const unsigned char* iv,
int iv_len,
unsigned int auth_tag_len);
void Init(const char* cipher_type,
const char* key_buf,
int key_buf_len,
unsigned int auth_tag_len);
void InitIv(const char* cipher_type,
const char* key,
const unsigned char* key,
int key_len,
const char* iv,
const unsigned char* iv,
int iv_len,
unsigned int auth_tag_len);
bool InitAuthenticated(const char* cipher_type, int iv_len,
Expand Down