@@ -47,6 +47,145 @@ bool IsSupportedAuthenticatedMode(const EVP_CIPHER_CTX* ctx) {
47
47
bool IsValidGCMTagLength (unsigned int tag_len) {
48
48
return tag_len == 4 || tag_len == 8 || (tag_len >= 12 && tag_len <= 16 );
49
49
}
50
+
51
+ // Collects and returns information on the given cipher
52
+ void GetCipherInfo (const FunctionCallbackInfo<Value>& args) {
53
+ Environment* env = Environment::GetCurrent (args);
54
+ CHECK (args[0 ]->IsObject ());
55
+ Local<Object> info = args[0 ].As <Object>();
56
+
57
+ CHECK (args[1 ]->IsString () || args[1 ]->IsInt32 ());
58
+
59
+ const EVP_CIPHER* cipher;
60
+ if (args[1 ]->IsString ()) {
61
+ Utf8Value name (env->isolate (), args[1 ]);
62
+ cipher = EVP_get_cipherbyname (*name);
63
+ } else {
64
+ int nid = args[1 ].As <Int32>()->Value ();
65
+ cipher = EVP_get_cipherbyname (OBJ_nid2sn (nid));
66
+ }
67
+
68
+ if (cipher == nullptr )
69
+ return ;
70
+
71
+ int mode = EVP_CIPHER_mode (cipher);
72
+ int iv_length = EVP_CIPHER_iv_length (cipher);
73
+ int key_length = EVP_CIPHER_key_length (cipher);
74
+ int block_length = EVP_CIPHER_block_size (cipher);
75
+ const char * mode_label = nullptr ;
76
+ switch (mode) {
77
+ case EVP_CIPH_CBC_MODE: mode_label = " cbc" ; break ;
78
+ case EVP_CIPH_CCM_MODE: mode_label = " ccm" ; break ;
79
+ case EVP_CIPH_CFB_MODE: mode_label = " cfb" ; break ;
80
+ case EVP_CIPH_CTR_MODE: mode_label = " ctr" ; break ;
81
+ case EVP_CIPH_ECB_MODE: mode_label = " ecb" ; break ;
82
+ case EVP_CIPH_GCM_MODE: mode_label = " gcm" ; break ;
83
+ case EVP_CIPH_OCB_MODE: mode_label = " ocb" ; break ;
84
+ case EVP_CIPH_OFB_MODE: mode_label = " ofb" ; break ;
85
+ case EVP_CIPH_WRAP_MODE: mode_label = " wrap" ; break ;
86
+ case EVP_CIPH_XTS_MODE: mode_label = " xts" ; break ;
87
+ case EVP_CIPH_STREAM_CIPHER: mode_label = " stream" ; break ;
88
+ }
89
+
90
+ // If the testKeyLen and testIvLen arguments are specified,
91
+ // then we will make an attempt to see if they are usable for
92
+ // the cipher in question, returning undefined if they are not.
93
+ // If they are, the info object will be returned with the values
94
+ // given.
95
+ if (args[2 ]->IsInt32 () || args[3 ]->IsInt32 ()) {
96
+ // Test and input IV or key length to determine if it's acceptable.
97
+ // If it is, then the getCipherInfo will succeed with the given
98
+ // values.
99
+ CipherCtxPointer ctx (EVP_CIPHER_CTX_new ());
100
+ if (!EVP_CipherInit_ex (ctx.get (), cipher, nullptr , nullptr , nullptr , 1 ))
101
+ return ;
102
+
103
+ if (args[2 ]->IsInt32 ()) {
104
+ int check_len = args[2 ].As <Int32>()->Value ();
105
+ if (!EVP_CIPHER_CTX_set_key_length (ctx.get (), check_len))
106
+ return ;
107
+ key_length = check_len;
108
+ }
109
+
110
+ if (args[3 ]->IsInt32 ()) {
111
+ int check_len = args[3 ].As <Int32>()->Value ();
112
+ // For CCM modes, the IV may be between 7 and 13 bytes.
113
+ // For GCM and OCB modes, we'll check by attempting to
114
+ // set the value. For everything else, just check that
115
+ // check_len == iv_length.
116
+ switch (mode) {
117
+ case EVP_CIPH_CCM_MODE:
118
+ if (check_len < 7 || check_len > 13 )
119
+ return ;
120
+ break ;
121
+ case EVP_CIPH_GCM_MODE:
122
+ // Fall through
123
+ case EVP_CIPH_OCB_MODE:
124
+ if (!EVP_CIPHER_CTX_ctrl (
125
+ ctx.get (),
126
+ EVP_CTRL_AEAD_SET_IVLEN,
127
+ check_len,
128
+ nullptr )) {
129
+ return ;
130
+ }
131
+ break ;
132
+ default :
133
+ if (check_len != iv_length)
134
+ return ;
135
+ }
136
+ iv_length = check_len;
137
+ }
138
+ }
139
+
140
+ if (mode_label != nullptr &&
141
+ info->Set (
142
+ env->context (),
143
+ FIXED_ONE_BYTE_STRING (env->isolate (), " mode" ),
144
+ OneByteString (env->isolate (), mode_label)).IsNothing ()) {
145
+ return ;
146
+ }
147
+
148
+ if (info->Set (
149
+ env->context (),
150
+ env->name_string (),
151
+ OneByteString (env->isolate (), EVP_CIPHER_name (cipher))).IsNothing ()) {
152
+ return ;
153
+ }
154
+
155
+ if (info->Set (
156
+ env->context (),
157
+ FIXED_ONE_BYTE_STRING (env->isolate (), " nid" ),
158
+ Int32::New (env->isolate (), EVP_CIPHER_nid (cipher))).IsNothing ()) {
159
+ return ;
160
+ }
161
+
162
+ // Stream ciphers do not have a meaningful block size
163
+ if (mode != EVP_CIPH_STREAM_CIPHER &&
164
+ info->Set (
165
+ env->context (),
166
+ FIXED_ONE_BYTE_STRING (env->isolate (), " blockSize" ),
167
+ Int32::New (env->isolate (), block_length)).IsNothing ()) {
168
+ return ;
169
+ }
170
+
171
+ // Ciphers that do not use an IV shouldn't report a length
172
+ if (iv_length != 0 &&
173
+ info->Set (
174
+ env->context (),
175
+ FIXED_ONE_BYTE_STRING (env->isolate (), " ivLength" ),
176
+ Int32::New (env->isolate (), iv_length)).IsNothing ()) {
177
+ return ;
178
+ }
179
+
180
+ if (info->Set (
181
+ env->context (),
182
+ FIXED_ONE_BYTE_STRING (env->isolate (), " keyLength" ),
183
+ Int32::New (env->isolate (), key_length)).IsNothing ()) {
184
+ return ;
185
+ }
186
+
187
+ args.GetReturnValue ().Set (info);
188
+ }
50
189
} // namespace
51
190
52
191
void CipherBase::GetSSLCiphers (const FunctionCallbackInfo<Value>& args) {
@@ -151,6 +290,8 @@ void CipherBase::Initialize(Environment* env, Local<Object> target) {
151
290
EVP_PKEY_verify_recover_init,
152
291
EVP_PKEY_verify_recover>);
153
292
293
+ env->SetMethodNoSideEffect (target, " getCipherInfo" , GetCipherInfo);
294
+
154
295
NODE_DEFINE_CONSTANT (target, kWebCryptoCipherEncrypt );
155
296
NODE_DEFINE_CONSTANT (target, kWebCryptoCipherDecrypt );
156
297
}
0 commit comments