mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-07 12:18:11 +00:00
292 lines
9.1 KiB
C++
292 lines
9.1 KiB
C++
#ifndef SRC_CRYPTO_CRYPTO_CIPHER_H_
|
|
#define SRC_CRYPTO_CRYPTO_CIPHER_H_
|
|
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
|
|
#include "crypto/crypto_keys.h"
|
|
#include "crypto/crypto_util.h"
|
|
#include "base_object.h"
|
|
#include "env.h"
|
|
#include "memory_tracker.h"
|
|
#include "v8.h"
|
|
|
|
#include <string>
|
|
|
|
namespace node {
|
|
namespace crypto {
|
|
class CipherBase : public BaseObject {
|
|
public:
|
|
static void GetSSLCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
|
|
|
void MemoryInfo(MemoryTracker* tracker) const override;
|
|
SET_MEMORY_INFO_NAME(CipherBase)
|
|
SET_SELF_SIZE(CipherBase)
|
|
|
|
protected:
|
|
enum CipherKind {
|
|
kCipher,
|
|
kDecipher
|
|
};
|
|
enum UpdateResult {
|
|
kSuccess,
|
|
kErrorMessageSize,
|
|
kErrorState
|
|
};
|
|
enum AuthTagState {
|
|
kAuthTagUnknown,
|
|
kAuthTagKnown,
|
|
kAuthTagPassedToOpenSSL
|
|
};
|
|
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 ArrayBufferOrViewContents<unsigned char>& key_buf,
|
|
unsigned int auth_tag_len);
|
|
void InitIv(const char* cipher_type,
|
|
const ByteSource& key_buf,
|
|
const ArrayBufferOrViewContents<unsigned char>& iv_buf,
|
|
unsigned int auth_tag_len);
|
|
bool InitAuthenticated(const char* cipher_type, int iv_len,
|
|
unsigned int auth_tag_len);
|
|
bool CheckCCMMessageLength(int message_len);
|
|
UpdateResult Update(const char* data, size_t len,
|
|
std::unique_ptr<v8::BackingStore>* out);
|
|
bool Final(std::unique_ptr<v8::BackingStore>* out);
|
|
bool SetAutoPadding(bool auto_padding);
|
|
|
|
bool IsAuthenticatedMode() const;
|
|
bool SetAAD(
|
|
const ArrayBufferOrViewContents<unsigned char>& data,
|
|
int plaintext_len);
|
|
bool MaybePassAuthTagToOpenSSL();
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void InitIv(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Update(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Final(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetAutoPadding(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void GetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetAAD(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
CipherBase(Environment* env, v8::Local<v8::Object> wrap, CipherKind kind);
|
|
|
|
private:
|
|
DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> ctx_;
|
|
const CipherKind kind_;
|
|
AuthTagState auth_tag_state_;
|
|
unsigned int auth_tag_len_;
|
|
char auth_tag_[EVP_GCM_TLS_TAG_LEN];
|
|
bool pending_auth_failed_;
|
|
int max_message_size_;
|
|
};
|
|
|
|
class PublicKeyCipher {
|
|
public:
|
|
typedef int (*EVP_PKEY_cipher_init_t)(EVP_PKEY_CTX* ctx);
|
|
typedef int (*EVP_PKEY_cipher_t)(EVP_PKEY_CTX* ctx,
|
|
unsigned char* out, size_t* outlen,
|
|
const unsigned char* in, size_t inlen);
|
|
|
|
enum Operation {
|
|
kPublic,
|
|
kPrivate
|
|
};
|
|
|
|
template <Operation operation,
|
|
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
static bool Cipher(Environment* env,
|
|
const ManagedEVPPKey& pkey,
|
|
int padding,
|
|
const EVP_MD* digest,
|
|
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
|
|
const ArrayBufferOrViewContents<unsigned char>& data,
|
|
std::unique_ptr<v8::BackingStore>* out);
|
|
|
|
template <Operation operation,
|
|
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
static void Cipher(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
};
|
|
|
|
enum WebCryptoCipherMode {
|
|
kWebCryptoCipherEncrypt,
|
|
kWebCryptoCipherDecrypt
|
|
};
|
|
|
|
enum class WebCryptoCipherStatus {
|
|
OK,
|
|
INVALID_KEY_TYPE,
|
|
FAILED
|
|
};
|
|
|
|
// CipherJob is a base implementation class for implementations of
|
|
// one-shot sync and async ciphers. It has been added primarily to
|
|
// support the AES and RSA ciphers underlying the WebCrypt API.
|
|
//
|
|
// See the crypto_aes and crypto_rsa headers for examples of how to
|
|
// use CipherJob.
|
|
template <typename CipherTraits>
|
|
class CipherJob final : public CryptoJob<CipherTraits> {
|
|
public:
|
|
using AdditionalParams = typename CipherTraits::AdditionalParameters;
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
CHECK(args.IsConstructCall());
|
|
|
|
CryptoJobMode mode = GetCryptoJobMode(args[0]);
|
|
|
|
CHECK(args[1]->IsUint32()); // Cipher Mode
|
|
|
|
uint32_t cmode = args[1].As<v8::Uint32>()->Value();
|
|
CHECK_LE(cmode, WebCryptoCipherMode::kWebCryptoCipherDecrypt);
|
|
WebCryptoCipherMode cipher_mode = static_cast<WebCryptoCipherMode>(cmode);
|
|
|
|
CHECK(args[2]->IsObject()); // KeyObject
|
|
KeyObjectHandle* key;
|
|
ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
|
|
CHECK_NOT_NULL(key);
|
|
|
|
ArrayBufferOrViewContents<char> data(args[3]); // data to operate on
|
|
if (!data.CheckSizeInt32())
|
|
return THROW_ERR_OUT_OF_RANGE(env, "data is too large");
|
|
|
|
AdditionalParams params;
|
|
if (CipherTraits::AdditionalConfig(mode, args, 4, cipher_mode, ¶ms)
|
|
.IsNothing()) {
|
|
// The CipherTraits::AdditionalConfig is responsible for
|
|
// calling an appropriate THROW_CRYPTO_* variant reporting
|
|
// whatever error caused initialization to fail.
|
|
return;
|
|
}
|
|
|
|
new CipherJob<CipherTraits>(
|
|
env,
|
|
args.This(),
|
|
mode,
|
|
key,
|
|
cipher_mode,
|
|
data,
|
|
std::move(params));
|
|
}
|
|
|
|
static void Initialize(
|
|
Environment* env,
|
|
v8::Local<v8::Object> target) {
|
|
CryptoJob<CipherTraits>::Initialize(New, env, target);
|
|
}
|
|
|
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|
CryptoJob<CipherTraits>::RegisterExternalReferences(New, registry);
|
|
}
|
|
|
|
CipherJob(
|
|
Environment* env,
|
|
v8::Local<v8::Object> object,
|
|
CryptoJobMode mode,
|
|
KeyObjectHandle* key,
|
|
WebCryptoCipherMode cipher_mode,
|
|
const ArrayBufferOrViewContents<char>& data,
|
|
AdditionalParams&& params)
|
|
: CryptoJob<CipherTraits>(
|
|
env,
|
|
object,
|
|
AsyncWrap::PROVIDER_CIPHERREQUEST,
|
|
mode,
|
|
std::move(params)),
|
|
key_(key->Data()),
|
|
cipher_mode_(cipher_mode),
|
|
in_(mode == kCryptoJobAsync
|
|
? data.ToCopy()
|
|
: data.ToByteSource()) {}
|
|
|
|
std::shared_ptr<KeyObjectData> key() const { return key_; }
|
|
|
|
WebCryptoCipherMode cipher_mode() const { return cipher_mode_; }
|
|
|
|
void DoThreadPoolWork() override {
|
|
const WebCryptoCipherStatus status =
|
|
CipherTraits::DoCipher(
|
|
AsyncWrap::env(),
|
|
key(),
|
|
cipher_mode_,
|
|
*CryptoJob<CipherTraits>::params(),
|
|
in_,
|
|
&out_);
|
|
if (status == WebCryptoCipherStatus::OK) {
|
|
// Success!
|
|
return;
|
|
}
|
|
CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
|
|
errors->Capture();
|
|
if (errors->Empty()) {
|
|
switch (status) {
|
|
case WebCryptoCipherStatus::OK:
|
|
UNREACHABLE();
|
|
break;
|
|
case WebCryptoCipherStatus::INVALID_KEY_TYPE:
|
|
errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
|
|
break;
|
|
case WebCryptoCipherStatus::FAILED:
|
|
errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
v8::Maybe<bool> ToResult(
|
|
v8::Local<v8::Value>* err,
|
|
v8::Local<v8::Value>* result) override {
|
|
Environment* env = AsyncWrap::env();
|
|
CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
|
|
|
|
if (errors->Empty())
|
|
errors->Capture();
|
|
|
|
if (out_.size() > 0 || errors->Empty()) {
|
|
CHECK(errors->Empty());
|
|
*err = v8::Undefined(env->isolate());
|
|
*result = out_.ToArrayBuffer(env);
|
|
return v8::Just(!result->IsEmpty());
|
|
}
|
|
|
|
*result = v8::Undefined(env->isolate());
|
|
return v8::Just(errors->ToException(env).ToLocal(err));
|
|
}
|
|
|
|
SET_SELF_SIZE(CipherJob)
|
|
void MemoryInfo(MemoryTracker* tracker) const override {
|
|
if (CryptoJob<CipherTraits>::mode() == kCryptoJobAsync)
|
|
tracker->TrackFieldWithSize("in", in_.size());
|
|
tracker->TrackFieldWithSize("out", out_.size());
|
|
CryptoJob<CipherTraits>::MemoryInfo(tracker);
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<KeyObjectData> key_;
|
|
WebCryptoCipherMode cipher_mode_;
|
|
ByteSource in_;
|
|
ByteSource out_;
|
|
};
|
|
|
|
} // namespace crypto
|
|
} // namespace node
|
|
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
#endif // SRC_CRYPTO_CRYPTO_CIPHER_H_
|