|
12 | 12 | namespace node { |
13 | 13 |
|
14 | 14 | using v8::Array; |
| 15 | +using v8::ArrayBuffer; |
| 16 | +using v8::BackingStore; |
15 | 17 | using v8::FunctionCallbackInfo; |
16 | 18 | using v8::FunctionTemplate; |
17 | 19 | using v8::HandleScope; |
@@ -752,7 +754,7 @@ void CipherBase::SetAAD(const FunctionCallbackInfo<Value>& args) { |
752 | 754 | CipherBase::UpdateResult CipherBase::Update( |
753 | 755 | const char* data, |
754 | 756 | size_t len, |
755 | | - AllocatedBuffer* out) { |
| 757 | + std::unique_ptr<BackingStore>* out) { |
756 | 758 | if (!ctx_ || len > INT_MAX) |
757 | 759 | return kErrorState; |
758 | 760 | MarkPopErrorOnReturn mark_pop_error_on_return; |
@@ -779,15 +781,22 @@ CipherBase::UpdateResult CipherBase::Update( |
779 | 781 | return kErrorState; |
780 | 782 | } |
781 | 783 |
|
782 | | - *out = AllocatedBuffer::AllocateManaged(env(), buf_len); |
| 784 | + { |
| 785 | + NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data()); |
| 786 | + *out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len); |
| 787 | + } |
| 788 | + |
783 | 789 | int r = EVP_CipherUpdate(ctx_.get(), |
784 | | - reinterpret_cast<unsigned char*>(out->data()), |
| 790 | + static_cast<unsigned char*>((*out)->Data()), |
785 | 791 | &buf_len, |
786 | 792 | reinterpret_cast<const unsigned char*>(data), |
787 | 793 | len); |
788 | 794 |
|
789 | | - CHECK_LE(static_cast<size_t>(buf_len), out->size()); |
790 | | - out->Resize(buf_len); |
| 795 | + CHECK_LE(static_cast<size_t>(buf_len), (*out)->ByteLength()); |
| 796 | + if (buf_len == 0) |
| 797 | + *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0); |
| 798 | + else |
| 799 | + *out = BackingStore::Reallocate(env()->isolate(), std::move(*out), buf_len); |
791 | 800 |
|
792 | 801 | // When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is |
793 | 802 | // invalid. In that case, remember the error and throw in final(). |
@@ -802,7 +811,7 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) { |
802 | 811 | Decode<CipherBase>(args, [](CipherBase* cipher, |
803 | 812 | const FunctionCallbackInfo<Value>& args, |
804 | 813 | const char* data, size_t size) { |
805 | | - AllocatedBuffer out; |
| 814 | + std::unique_ptr<BackingStore> out; |
806 | 815 | Environment* env = Environment::GetCurrent(args); |
807 | 816 |
|
808 | 817 | if (UNLIKELY(size > INT_MAX)) |
@@ -818,8 +827,9 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) { |
818 | 827 | return; |
819 | 828 | } |
820 | 829 |
|
821 | | - CHECK(out.data() != nullptr || out.size() == 0); |
822 | | - args.GetReturnValue().Set(out.ToBuffer().FromMaybe(Local<Value>())); |
| 830 | + Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out)); |
| 831 | + args.GetReturnValue().Set( |
| 832 | + Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>())); |
823 | 833 | }); |
824 | 834 | } |
825 | 835 |
|
@@ -838,36 +848,40 @@ void CipherBase::SetAutoPadding(const FunctionCallbackInfo<Value>& args) { |
838 | 848 | args.GetReturnValue().Set(b); // Possibly report invalid state failure |
839 | 849 | } |
840 | 850 |
|
841 | | -bool CipherBase::Final(AllocatedBuffer* out) { |
| 851 | +bool CipherBase::Final(std::unique_ptr<BackingStore>* out) { |
842 | 852 | if (!ctx_) |
843 | 853 | return false; |
844 | 854 |
|
845 | 855 | const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); |
846 | 856 |
|
847 | | - *out = AllocatedBuffer::AllocateManaged( |
848 | | - env(), |
849 | | - static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get()))); |
| 857 | + { |
| 858 | + NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data()); |
| 859 | + *out = ArrayBuffer::NewBackingStore(env()->isolate(), |
| 860 | + static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get()))); |
| 861 | + } |
850 | 862 |
|
851 | | - if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get())) { |
| 863 | + if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get())) |
852 | 864 | MaybePassAuthTagToOpenSSL(); |
853 | | - } |
854 | 865 |
|
855 | 866 | // In CCM mode, final() only checks whether authentication failed in update(). |
856 | 867 | // EVP_CipherFinal_ex must not be called and will fail. |
857 | 868 | bool ok; |
858 | 869 | if (kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) { |
859 | 870 | ok = !pending_auth_failed_; |
860 | | - *out = AllocatedBuffer::AllocateManaged(env(), 0); // Empty buffer. |
| 871 | + *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0); |
861 | 872 | } else { |
862 | | - int out_len = out->size(); |
| 873 | + int out_len = (*out)->ByteLength(); |
863 | 874 | ok = EVP_CipherFinal_ex(ctx_.get(), |
864 | | - reinterpret_cast<unsigned char*>(out->data()), |
| 875 | + static_cast<unsigned char*>((*out)->Data()), |
865 | 876 | &out_len) == 1; |
866 | 877 |
|
867 | | - if (out_len >= 0) |
868 | | - out->Resize(out_len); |
869 | | - else |
870 | | - *out = AllocatedBuffer(); // *out will not be used. |
| 878 | + CHECK_LE(static_cast<size_t>(out_len), (*out)->ByteLength()); |
| 879 | + if (out_len > 0) { |
| 880 | + *out = |
| 881 | + BackingStore::Reallocate(env()->isolate(), std::move(*out), out_len); |
| 882 | + } else { |
| 883 | + *out = ArrayBuffer::NewBackingStore(env()->isolate(), 0); |
| 884 | + } |
871 | 885 |
|
872 | 886 | if (ok && kind_ == kCipher && IsAuthenticatedMode()) { |
873 | 887 | // In GCM mode, the authentication tag length can be specified in advance, |
@@ -896,7 +910,7 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) { |
896 | 910 | if (cipher->ctx_ == nullptr) |
897 | 911 | return THROW_ERR_CRYPTO_INVALID_STATE(env); |
898 | 912 |
|
899 | | - AllocatedBuffer out; |
| 913 | + std::unique_ptr<BackingStore> out; |
900 | 914 |
|
901 | 915 | // Check IsAuthenticatedMode() first, Final() destroys the EVP_CIPHER_CTX. |
902 | 916 | const bool is_auth_mode = cipher->IsAuthenticatedMode(); |
@@ -910,7 +924,9 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) { |
910 | 924 | return ThrowCryptoError(env, ERR_get_error(), msg); |
911 | 925 | } |
912 | 926 |
|
913 | | - args.GetReturnValue().Set(out.ToBuffer().FromMaybe(Local<Value>())); |
| 927 | + Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out)); |
| 928 | + args.GetReturnValue().Set( |
| 929 | + Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>())); |
914 | 930 | } |
915 | 931 |
|
916 | 932 | template <PublicKeyCipher::Operation operation, |
@@ -923,7 +939,7 @@ bool PublicKeyCipher::Cipher( |
923 | 939 | const EVP_MD* digest, |
924 | 940 | const ArrayBufferOrViewContents<unsigned char>& oaep_label, |
925 | 941 | const ArrayBufferOrViewContents<unsigned char>& data, |
926 | | - AllocatedBuffer* out) { |
| 942 | + std::unique_ptr<BackingStore>* out) { |
927 | 943 | EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); |
928 | 944 | if (!ctx) |
929 | 945 | return false; |
@@ -959,18 +975,26 @@ bool PublicKeyCipher::Cipher( |
959 | 975 | return false; |
960 | 976 | } |
961 | 977 |
|
962 | | - *out = AllocatedBuffer::AllocateManaged(env, out_len); |
| 978 | + { |
| 979 | + NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data()); |
| 980 | + *out = ArrayBuffer::NewBackingStore(env->isolate(), out_len); |
| 981 | + } |
963 | 982 |
|
964 | 983 | if (EVP_PKEY_cipher( |
965 | 984 | ctx.get(), |
966 | | - reinterpret_cast<unsigned char*>(out->data()), |
| 985 | + static_cast<unsigned char*>((*out)->Data()), |
967 | 986 | &out_len, |
968 | 987 | data.data(), |
969 | 988 | data.size()) <= 0) { |
970 | 989 | return false; |
971 | 990 | } |
972 | 991 |
|
973 | | - out->Resize(out_len); |
| 992 | + CHECK_LE(out_len, (*out)->ByteLength()); |
| 993 | + if (out_len > 0) |
| 994 | + *out = BackingStore::Reallocate(env->isolate(), std::move(*out), out_len); |
| 995 | + else |
| 996 | + *out = ArrayBuffer::NewBackingStore(env->isolate(), 0); |
| 997 | + |
974 | 998 | return true; |
975 | 999 | } |
976 | 1000 |
|
@@ -1009,15 +1033,15 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) { |
1009 | 1033 | return THROW_ERR_OUT_OF_RANGE(env, "oaep_label is too big"); |
1010 | 1034 | } |
1011 | 1035 |
|
1012 | | - AllocatedBuffer out; |
| 1036 | + std::unique_ptr<BackingStore> out; |
1013 | 1037 | if (!Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>( |
1014 | 1038 | env, pkey, padding, digest, oaep_label, buf, &out)) { |
1015 | 1039 | return ThrowCryptoError(env, ERR_get_error()); |
1016 | 1040 | } |
1017 | 1041 |
|
1018 | | - Local<Value> result; |
1019 | | - if (out.ToBuffer().ToLocal(&result)) |
1020 | | - args.GetReturnValue().Set(result); |
| 1042 | + Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(out)); |
| 1043 | + args.GetReturnValue().Set( |
| 1044 | + Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>())); |
1021 | 1045 | } |
1022 | 1046 |
|
1023 | 1047 | } // namespace crypto |
|