logstash-filter-cipher 2.0.6 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cbca0f8a8e9f7238c622ddddd6b3bea364bc7593
4
- data.tar.gz: 25501d5359ee6bd2294ef782c9d24845fe0a7880
2
+ SHA256:
3
+ metadata.gz: 46b796b1a113a179ffd905368531092245493669a2cd8f9ad7a40f5a70bf93c0
4
+ data.tar.gz: d8cdd9b1516c58531124337c8a80c084ce1b64e34b1a9fc2bafc13f95a899b2d
5
5
  SHA512:
6
- metadata.gz: 356b67cc860424b7da5c28f865de3faea3d1db4fdafee60cabcc64c960762319d39d6d8050cdcb182d0fea116d8893f476b1a14301558b9b37b2ed97eadc24ba
7
- data.tar.gz: 9686860078d4b348ed59d19643cbc4d30dfbc60b13a604da32e41f0341e616031eef0c4e0e17cd92871a0aa0689cfa28921e60602ed88533c8da7cc77739ea3a
6
+ metadata.gz: 87e5034edcfdc5d8f2a6e41e41e92dd0b775e26dd463f167e026bfa4a543a37a9a07bed65882fa72206c893a7c9962657434af4f4013dd166a184a5deb02a6ad
7
+ data.tar.gz: 6e79143228ccef00b0495d446c5780683e6c94cc8ce67e12781c0f24a780cc2ac62a68e3be289dc232df1995b879a8407468f33b57e924f2dc9b11a6ee8d539e
@@ -1,12 +1,33 @@
1
- # 2.0.5
2
- - Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
3
- # 2.0.4
4
- - New dependency requirements for logstash-core for the 5.0 release
1
+ ## 4.0.1
2
+ - General improvements to code and docs [#29](https://github.com/logstash-plugins/logstash-filter-cipher/pull/29)
3
+ - Fixed threadsafety; this plugin can now be used in pipelines with more than one worker.
4
+ - Fixed a potential leak of the configured key into logs; the key is now only included if trace-level logging is enabled.
5
+ - Fixed an issue where configurations that used invalid `mode` or `algorithm` settings could produce unhelpful error messages.
6
+ - Fixed an issue where a bad payload could cause the plugin to crash; when exceptions are encountered, the offending event will now be tagged with `_cipherfiltererror`.
7
+ - Improved documentation substantially.
8
+
9
+ ## 4.0.0
10
+ - Removed obsolete iv field
11
+
12
+ ## 3.0.1
13
+ - Update gemspec summary
14
+
15
+ ## 3.0.0
16
+ - Mark deprecated iv field obsolete
17
+
18
+ ## 2.0.7
19
+ - Fix some documentation issues
20
+
21
+ ## 2.0.5
22
+ - internal,deps: Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
23
+
24
+ ## 2.0.4
25
+ - internal,deps: New dependency requirements for logstash-core for the 5.0 release
26
+
5
27
  ## 2.0.3
6
- - fixes base64 encoding issue, adds support for random IVs
28
+ - bugfix: fixes base64 encoding issue, adds support for random IVs
7
29
 
8
30
  ## 2.0.0
9
- - Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
31
+ - internal: Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
10
32
  instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
11
- - Dependency on logstash-core update to 2.0
12
-
33
+ - internal,deps: Dependency on logstash-core update to 2.0
data/LICENSE CHANGED
@@ -1,13 +1,202 @@
1
- Copyright (c) 2012–2016 Elasticsearch <http://www.elastic.co>
2
1
 
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License.
5
- You may obtain a copy of the License at
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
6
5
 
7
- http://www.apache.org/licenses/LICENSE-2.0
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
7
 
9
- Unless required by applicable law or agreed to in writing, software
10
- distributed under the License is distributed on an "AS IS" BASIS,
11
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- See the License for the specific language governing permissions and
13
- limitations under the License.
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2020 Elastic and contributors
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -12,7 +12,7 @@ START - GENERATED VARIABLES, DO NOT EDIT!
12
12
  END - GENERATED VARIABLES, DO NOT EDIT!
13
13
  ///////////////////////////////////////////
14
14
 
15
- [id="plugins-{type}-{plugin}"]
15
+ [id="plugins-{type}s-{plugin}"]
16
16
 
17
17
  === Cipher filter plugin
18
18
 
@@ -23,6 +23,9 @@ include::{include_path}/plugin_header.asciidoc[]
23
23
  This filter parses a source and apply a cipher or decipher before
24
24
  storing it in the target.
25
25
 
26
+ NOTE: Prior to version 4.0.1, this plugin was not thread-safe and
27
+ could not safely be used with multiple pipeline workers.
28
+
26
29
 
27
30
  [id="plugins-{type}s-{plugin}-options"]
28
31
  ==== Cipher Filter Configuration Options
@@ -37,7 +40,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
37
40
  | <<plugins-{type}s-{plugin}-cipher_padding>> |<<string,string>>|No
38
41
  | <<plugins-{type}s-{plugin}-iv_random_length>> |<<number,number>>|No
39
42
  | <<plugins-{type}s-{plugin}-key>> |<<string,string>>|No
40
- | <<plugins-{type}s-{plugin}-key_pad>> |<<,>>|No
43
+ | <<plugins-{type}s-{plugin}-key_pad>> |<<string,string>>|No
41
44
  | <<plugins-{type}s-{plugin}-key_size>> |<<number,number>>|No
42
45
  | <<plugins-{type}s-{plugin}-max_cipher_reuse>> |<<number,number>>|No
43
46
  | <<plugins-{type}s-{plugin}-mode>> |<<string,string>>|Yes
@@ -57,89 +60,63 @@ filter plugins.
57
60
  * Value type is <<string,string>>
58
61
  * There is no default value for this setting.
59
62
 
60
- The cipher algorithm
63
+ The cipher algorithm to use for encryption and decryption operations.
61
64
 
62
- A list of supported algorithms can be obtained by
63
- [source,ruby]
64
- puts OpenSSL::Cipher.ciphers
65
+ A list of supported algorithms depends on the versions of Logstash, JRuby, and Java this plugin is running in, but can be obtained by running:
66
+ [source,sh]
67
+ cd $LOGSTASH_HOME # <-- your Logstash distribution root
68
+ bin/ruby -ropenssl -e 'puts OpenSSL::Cipher.ciphers'
65
69
 
66
70
  [id="plugins-{type}s-{plugin}-base64"]
67
71
  ===== `base64`
68
72
 
69
73
  * Value type is <<boolean,boolean>>
70
74
  * Default value is `true`
71
-
72
- Do we have to perform a `base64` decode or encode?
73
-
74
- If we are decrypting, `base64` decode will be done before.
75
- If we are encrypting, `base64` will be done after.
75
+ * Unless this option is disabled:
76
+ ** When <<plugins-{type}s-{plugin}-mode,`mode => encrypt`>>, the source ciphertext will be `base64`-decoded before it is deciphered.
77
+ ** When <<plugins-{type}s-{plugin}-mode,`mode => decrypt`>>, the result ciphertext will be `base64`-encoded before it is stored.
76
78
 
77
79
 
78
80
  [id="plugins-{type}s-{plugin}-cipher_padding"]
79
81
  ===== `cipher_padding`
80
82
 
81
83
  * Value type is <<string,string>>
84
+ ** `0`: means `false`
85
+ ** `1`: means `true`
82
86
  * There is no default value for this setting.
83
87
 
84
- Cipher padding to use. Enables or disables padding.
88
+ Enables or disables padding in encryption operations.
85
89
 
86
- By default encryption operations are padded using standard block padding
87
- and the padding is checked and removed when decrypting. If the pad
88
- parameter is zero then no padding is performed, the total amount of data
89
- encrypted or decrypted must then be a multiple of the block size or an
90
- error will occur.
90
+ In encryption operations with block-ciphers, the input plaintext must be
91
+ an _exact_ multiple of the cipher's block-size unless padding is enabled.
91
92
 
92
- See EVP_CIPHER_CTX_set_padding for further information.
93
+ Disabling padding by setting this value to `0` will cause this plugin to
94
+ fail to encrypt any input plaintext that doesn't strictly adhere to the
95
+ <<plugins-{type}s-{plugin}-algorithm>>'s block size requirements.
93
96
 
94
- We are using Openssl jRuby which uses default padding to PKCS5Padding
95
- If you want to change it, set this parameter. If you want to disable
96
- it, Set this parameter to 0
97
97
  [source,ruby]
98
98
  filter { cipher { cipher_padding => 0 }}
99
99
 
100
- [id="plugins-{type}s-{plugin}-iv"]
101
- ===== `iv` (DEPRECATED)
102
-
103
- * DEPRECATED WARNING: This configuration item is deprecated and may not be available in future versions.
104
- * Value type is <<string,string>>
105
- * There is no default value for this setting.
106
-
107
- The initialization vector to use (statically hard-coded). For
108
- a random IV see the iv_random_length property
109
-
110
- NOTE: If iv_random_length is set, it takes precedence over any value set for "iv"
111
-
112
- The cipher modes CBC, CFB, OFB and CTR all need an "initialization
113
- vector", or short, IV. ECB mode is the only mode that does not require
114
- an IV, but there is almost no legitimate use case for this mode
115
- because of the fact that it does not sufficiently hide plaintext patterns.
116
-
117
- For AES algorithms set this to a 16 byte string.
118
- [source,ruby]
119
- filter { cipher { iv => "1234567890123456" }}
120
-
121
- Deprecated: Please use `iv_random_length` instead
122
-
123
100
  [id="plugins-{type}s-{plugin}-iv_random_length"]
124
101
  ===== `iv_random_length`
125
102
 
126
103
  * Value type is <<number,number>>
127
104
  * There is no default value for this setting.
128
105
 
129
- Force an random IV to be used per encryption invocation and specify
130
- the length of the random IV that will be generated via:
131
-
132
- OpenSSL::Random.random_bytes(int_length)
106
+ In encryption operations, this plugin generates a random Initialization
107
+ Vector (IV) per encryption operation. This is a standard best-practice to ensure
108
+ that the resulting ciphertexts cannot be compared to infer equivalence
109
+ of the source plaintext. This unique IV is then _prepended_ to the resulting
110
+ ciphertext before it is stored, ensuring it is available to any process
111
+ that needs to decrypt it.
133
112
 
134
- If iv_random_length is set, it takes precedence over any value set for "iv"
113
+ In decryption operations, the IV is assumed to have been prepended to
114
+ the ciphertext, so this plugin needs to know the length of the IV in
115
+ order to split the input appropriately.
135
116
 
136
- Enabling this will force the plugin to generate a unique
137
- random IV for each encryption call. This random IV will be prepended to the
138
- encrypted result bytes and then base64 encoded. On decryption "iv_random_length" must
139
- also be set to utilize this feature. Random IV's are better than statically
140
- hardcoded IVs
117
+ The size of the IV is generally dependent on which <<plugins-{type}s-{plugin}-algorithm>>
118
+ is used. AES Algorithms generally use a 16-byte IV:
141
119
 
142
- For AES algorithms you can set this to a 16
143
120
  [source,ruby]
144
121
  filter { cipher { iv_random_length => 16 }}
145
122
 
@@ -149,7 +126,7 @@ For AES algorithms you can set this to a 16
149
126
  * Value type is <<string,string>>
150
127
  * There is no default value for this setting.
151
128
 
152
- The key to use
129
+ The key to use for encryption and decryption operations.
153
130
 
154
131
  NOTE: If you encounter an error message at runtime containing the following:
155
132
 
@@ -165,7 +142,7 @@ Please read the following: https://github.com/jruby/jruby/wiki/UnlimitedStrength
165
142
  * Value type is <<string,string>>
166
143
  * Default value is `"\u0000"`
167
144
 
168
- The character used to pad the key
145
+ The character used to pad the key to the required <<plugins-{type}s-{plugin}-key_size>>.
169
146
 
170
147
  [id="plugins-{type}s-{plugin}-key_size"]
171
148
  ===== `key_size`
@@ -173,10 +150,9 @@ The character used to pad the key
173
150
  * Value type is <<number,number>>
174
151
  * Default value is `16`
175
152
 
176
- The key size to pad
177
-
178
- It depends of the cipher algorithm. If your key doesn't need
179
- padding, don't set this parameter
153
+ The cipher's required key size, which depends on which <<plugins-{type}s-{plugin}-algorithm>>
154
+ you are using. If a <<plugins-{type}s-{plugin}-key>> is specified with a shorter value,
155
+ it will be padded with <<plugins-{type}s-{plugin}-key_pad>>.
180
156
 
181
157
  Example, for AES-128, we must have 16 char long key. AES-256 = 32 chars
182
158
  [source,ruby]
@@ -189,9 +165,9 @@ Example, for AES-128, we must have 16 char long key. AES-256 = 32 chars
189
165
  * Value type is <<number,number>>
190
166
  * Default value is `1`
191
167
 
192
- If this is set the internal Cipher instance will be
193
- re-used up to @max_cipher_reuse times before being
194
- reset() and re-created from scratch. This is an option
168
+ If this value is set, the internal Cipher instance will be
169
+ re-used up to `max_cipher_reuse` times before it is re-created
170
+ from scratch. This is an option
195
171
  for efficiency where lots of data is being encrypted
196
172
  and decrypted using this filter. This lets the filter
197
173
  avoid creating new Cipher instances over and over
@@ -207,21 +183,22 @@ instance and max_cipher_reuse = 1 by default
207
183
 
208
184
  * This is a required setting.
209
185
  * Value type is <<string,string>>
186
+ ** `encrypt`: encrypts a plaintext value into IV + ciphertext
187
+ ** `decrypt`: decrypts an IV + ciphertext value into plaintext
210
188
  * There is no default value for this setting.
211
189
 
212
- Encrypting or decrypting some data
213
-
214
- Valid values are encrypt or decrypt
215
-
216
190
  [id="plugins-{type}s-{plugin}-source"]
217
191
  ===== `source`
218
192
 
219
193
  * Value type is <<string,string>>
220
194
  * Default value is `"message"`
221
195
 
222
- The field to perform filter
196
+ The name of the source field.
223
197
 
224
- Example, to use the @message field (default) :
198
+ * When <<plugins-{type}s-{plugin}-mode,`mode => encrypt`>>, the `source` should be a field containing plaintext
199
+ * When <<plugins-{type}s-{plugin}-mode,`mode => decrypt`>>, the `source` should be a field containing IV + ciphertext
200
+
201
+ Example, to use the `message` field (default) :
225
202
  [source,ruby]
226
203
  filter { cipher { source => "message" } }
227
204
 
@@ -231,13 +208,16 @@ Example, to use the @message field (default) :
231
208
  * Value type is <<string,string>>
232
209
  * Default value is `"message"`
233
210
 
234
- The name of the container to put the result
211
+ The name of the target field to put the result:
212
+
213
+ * When <<plugins-{type}s-{plugin}-mode,`mode => encrypt`>>, the IV + ciphertext result will be stored in the `target` field
214
+ * When <<plugins-{type}s-{plugin}-mode,`mode => decrypt`>>, the plaintext result will be stored in the `target` field
235
215
 
236
- Example, to place the result into crypt :
216
+ Example, to place the result into crypt:
237
217
  [source,ruby]
238
218
  filter { cipher { target => "crypt" } }
239
219
 
240
220
 
241
221
 
242
222
  [id="plugins-{type}s-{plugin}-common-options"]
243
- include::{include_path}/{type}.asciidoc[]
223
+ include::{include_path}/{type}.asciidoc[]
@@ -1,8 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/filters/base"
3
- require "logstash/namespace"
4
3
  require "openssl"
5
-
4
+ require "concurrent/atomic/thread_local_var"
6
5
 
7
6
  # This filter parses a source and apply a cipher or decipher before
8
7
  # storing it in the target.
@@ -40,7 +39,7 @@ class LogStash::Filters::Cipher < LogStash::Filters::Base
40
39
  #
41
40
  # Please read the following: https://github.com/jruby/jruby/wiki/UnlimitedStrengthCrypto
42
41
  #
43
- config :key, :validate => :string
42
+ config :key, :validate => :password
44
43
 
45
44
  # The key size to pad
46
45
  #
@@ -61,12 +60,12 @@ class LogStash::Filters::Cipher < LogStash::Filters::Base
61
60
  # A list of supported algorithms can be obtained by
62
61
  # [source,ruby]
63
62
  # puts OpenSSL::Cipher.ciphers
64
- config :algorithm, :validate => :string, :required => true
63
+ config :algorithm, :validate => OpenSSL::Cipher.ciphers, :required => true
65
64
 
66
65
  # Encrypting or decrypting some data
67
66
  #
68
67
  # Valid values are encrypt or decrypt
69
- config :mode, :validate => :string, :required => true
68
+ config :mode, :validate => %w(encrypt decrypt), :required => true
70
69
 
71
70
  # Cipher padding to use. Enables or disables padding.
72
71
  #
@@ -85,30 +84,11 @@ class LogStash::Filters::Cipher < LogStash::Filters::Base
85
84
  # filter { cipher { cipher_padding => 0 }}
86
85
  config :cipher_padding, :validate => :string
87
86
 
88
- # The initialization vector to use (statically hard-coded). For
89
- # a random IV see the iv_random_length property
90
- #
91
- # NOTE: If iv_random_length is set, it takes precedence over any value set for "iv"
92
- #
93
- # The cipher modes CBC, CFB, OFB and CTR all need an "initialization
94
- # vector", or short, IV. ECB mode is the only mode that does not require
95
- # an IV, but there is almost no legitimate use case for this mode
96
- # because of the fact that it does not sufficiently hide plaintext patterns.
97
- #
98
- # For AES algorithms set this to a 16 byte string.
99
- # [source,ruby]
100
- # filter { cipher { iv => "1234567890123456" }}
101
- #
102
- # Deprecated: Please use `iv_random_length` instead
103
- config :iv, :validate => :string, :deprecated => "Please use 'iv_random_length'"
104
-
105
87
  # Force an random IV to be used per encryption invocation and specify
106
88
  # the length of the random IV that will be generated via:
107
89
  #
108
90
  # OpenSSL::Random.random_bytes(int_length)
109
91
  #
110
- # If iv_random_length is set, it takes precedence over any value set for "iv"
111
- #
112
92
  # Enabling this will force the plugin to generate a unique
113
93
  # random IV for each encryption call. This random IV will be prepended to the
114
94
  # encrypted result bytes and then base64 encoded. On decryption "iv_random_length" must
@@ -118,7 +98,7 @@ class LogStash::Filters::Cipher < LogStash::Filters::Base
118
98
  # For AES algorithms you can set this to a 16
119
99
  # [source,ruby]
120
100
  # filter { cipher { iv_random_length => 16 }}
121
- config :iv_random_length, :validate => :number
101
+ config :iv_random_length, :validate => :number, :required => true
122
102
 
123
103
  # If this is set the internal Cipher instance will be
124
104
  # re-used up to @max_cipher_reuse times before being
@@ -136,120 +116,158 @@ class LogStash::Filters::Cipher < LogStash::Filters::Base
136
116
 
137
117
  def register
138
118
  require 'base64' if @base64
139
- init_cipher
140
- end # def register
119
+ if cipher_reuse_enabled?
120
+ @reusable_cipher = Concurrent::ThreadLocalVar.new
121
+ @cipher_reuse_count = Concurrent::ThreadLocalVar.new
122
+ end
141
123
 
124
+ if @key.value.length != @key_size
125
+ @logger.debug("key length is " + @key.length.to_s + ", padding it to " + @key_size.to_s + " with '" + @key_pad.to_s + "'")
126
+ @key = @key.class.new(@key.value[0,@key_size].ljust(@key_size,@key_pad))
127
+ end
128
+ end # def register
142
129
 
143
130
  def filter(event)
144
-
145
-
146
-
147
- #If decrypt or encrypt fails, we keep it it intact.
148
- begin
149
-
150
- if (event[@source].nil? || event[@source].empty?)
151
- @logger.debug("Event to filter, event 'source' field: " + @source + " was null(nil) or blank, doing nothing")
152
- return
153
- end
154
-
155
- #@logger.debug("Event to filter", :event => event)
156
- data = event[@source]
157
- if @mode == "decrypt"
158
- data = Base64.strict_decode64(data) if @base64 == true
159
-
160
- if !@iv_random_length.nil?
161
- @random_iv = data.byteslice(0,@iv_random_length)
162
- data = data.byteslice(@iv_random_length..data.length)
163
- end
164
-
165
- end
166
-
167
- if !@iv_random_length.nil? and @mode == "encrypt"
168
- @random_iv = OpenSSL::Random.random_bytes(@iv_random_length)
169
- end
170
-
171
- # if iv_random_length is specified, generate a new one
172
- # and force the cipher's IV = to the random value
173
- if !@iv_random_length.nil?
174
- @cipher.iv = @random_iv
175
- end
176
-
177
- result = @cipher.update(data) + @cipher.final
178
-
179
- if @mode == "encrypt"
180
-
181
- # if we have a random_iv, prepend that to the crypted result
182
- if !@random_iv.nil?
183
- result = @random_iv + result
184
- end
185
-
186
- result = Base64.strict_encode64(result).encode("utf-8") if @base64 == true
187
- end
131
+ source = event.get(@source)
132
+ if (source.nil? || source.empty?)
133
+ @logger.debug("Event to filter, event 'source' field: " + @source + " was null(nil) or blank, doing nothing")
134
+ return
135
+ end
188
136
 
189
- rescue => e
190
- @logger.warn("Exception catch on cipher filter", :event => event, :error => e)
137
+ result = case(@mode)
138
+ when "encrypt" then do_encrypt(source)
139
+ when "decrypt" then do_decrypt(source)
140
+ else
141
+ @logger.error("Invalid cipher mode. Valid values are \"encrypt\" or \"decrypt\"", :mode => @mode)
142
+ raise "Internal Error, aborting."
143
+ end
191
144
 
192
- # force a re-initialize on error to be safe
193
- init_cipher
145
+ event.set(@target, result)
146
+ filter_matched(event) unless result.nil?
147
+ rescue => e
148
+ @logger.error("An error occurred while #{@mode}ing.", :exception => e.message)
149
+ event.tag("_cipherfiltererror")
150
+ end
194
151
 
195
- else
196
- @total_cipher_uses += 1
152
+ private
197
153
 
198
- result = result.force_encoding("utf-8") if @mode == "decrypt"
154
+ def cipher_reuse_enabled?
155
+ @max_cipher_reuse > 1
156
+ end
199
157
 
200
- event[@target]= result
158
+ ##
159
+ # @param plaintext [String]
160
+ # @return [String]: ciphertext
161
+ def do_encrypt(plaintext)
162
+ with_cipher do |cipher|
163
+ random_iv = OpenSSL::Random.random_bytes(@iv_random_length)
164
+ cipher.iv = random_iv
201
165
 
202
- #Is it necessary to add 'if !result.nil?' ? exception have been already catched.
203
- #In doubt, I keep it.
204
- filter_matched(event) if !result.nil?
166
+ ciphertext = random_iv + cipher.update(plaintext) + cipher.final
205
167
 
206
- if !@max_cipher_reuse.nil? and @total_cipher_uses >= @max_cipher_reuse
207
- @logger.debug("max_cipher_reuse["+@max_cipher_reuse.to_s+"] reached, total_cipher_uses = "+@total_cipher_uses.to_s)
208
- init_cipher
209
- end
168
+ ciphertext = Base64.strict_encode64(ciphertext).encode("utf-8") if @base64 == true
210
169
 
170
+ ciphertext
211
171
  end
212
- end # def filter
213
-
214
- def init_cipher
172
+ end
173
+
174
+ ##
175
+ # @param ciphertext_with_iv [String]
176
+ # @return [String] plaintext
177
+ def do_decrypt(ciphertext_with_iv)
178
+ ciphertext_with_iv = Base64.strict_decode64(ciphertext_with_iv) if @base64 == true
179
+ encoded_iv = ciphertext_with_iv.byteslice(0..@iv_random_length)
180
+ ciphertext = ciphertext_with_iv.byteslice(@iv_random_length..-1)
181
+
182
+ with_cipher do |cipher|
183
+ cipher.iv = encoded_iv
184
+ plaintext = cipher.update(ciphertext) + cipher.final
185
+ plaintext.force_encoding("UTF-8")
186
+ plaintext
187
+ end
188
+ end
215
189
 
216
- if !@cipher.nil?
217
- @cipher.reset
218
- @cipher = nil
190
+ ##
191
+ # Returns a new or freshly-reset cipher, bypassing cipher reuse if it is not enabled
192
+ #
193
+ # @yieldparam [OpenSSL::Cipher]
194
+ # @yieldreturn [Object]: the object that this method should return
195
+ # @return [Object]: the object that was returned by the yielded block
196
+ def with_cipher
197
+ return yield(init_cipher) unless cipher_reuse_enabled?
198
+
199
+ with_reusable_cipher do |reusable_cipher|
200
+ yield reusable_cipher
219
201
  end
202
+ end
220
203
 
221
- @cipher = OpenSSL::Cipher.new(@algorithm)
204
+ ##
205
+ # Returns a new or freshly-reset cipher.
206
+ #
207
+ # @yieldparam [OpenSSL::Cipher]
208
+ # @yieldreturn [Object]: the object that this method should return
209
+ # @return [Object]: the object that was returned by the yielded block
210
+ def with_reusable_cipher
211
+ cipher = get_or_init_reusable_cipher
212
+
213
+ result = yield(cipher)
214
+
215
+ cleanup_reusable_cipher
216
+
217
+ return result
218
+ rescue => e
219
+ # when an error is encountered, we cannot trust the state of the cipher object.
220
+ @logger.debug("shared cipher: removing because an exception was raised in #{Thread.current}", :exception => e.message)
221
+ destroy_reusable_cipher
222
+ raise
223
+ end
224
+
225
+ def get_or_init_reusable_cipher
226
+ if @reusable_cipher.value.nil?
227
+ @logger.debug("shared cipher: initializing for #{Thread.current}")
228
+ @reusable_cipher.value = init_cipher
229
+ @cipher_reuse_count.value = 0
230
+ end
222
231
 
223
- @total_cipher_uses = 0
232
+ @cipher_reuse_count.value += 1
233
+ @reusable_cipher.value
234
+ end
224
235
 
225
- if @mode == "encrypt"
226
- @cipher.encrypt
227
- elsif @mode == "decrypt"
228
- @cipher.decrypt
236
+ def cleanup_reusable_cipher
237
+ if @cipher_reuse_count.value >= @max_cipher_reuse
238
+ @logger.debug("shared cipher: max_cipher_reuse[#{@max_cipher_reuse}] reached for #{Thread.current}, total_cipher_uses = #{@cipher_reuse_count.value}") if @logger.debug?
239
+ destroy_reusable_cipher
229
240
  else
230
- @logger.error("Invalid cipher mode. Valid values are \"encrypt\" or \"decrypt\"", :mode => @mode)
231
- raise "Bad configuration, aborting."
241
+ @logger.debug("shared cipher: resetting for #{Thread.current}")
242
+ @reusable_cipher.value.reset
232
243
  end
244
+ end
233
245
 
234
- if @key.length != @key_size
235
- @logger.debug("key length is " + @key.length.to_s + ", padding it to " + @key_size.to_s + " with '" + @key_pad.to_s + "'")
236
- @key = @key[0,@key_size].ljust(@key_size,@key_pad)
237
- end
246
+ def destroy_reusable_cipher
247
+ @reusable_cipher.value = nil
248
+ @cipher_reuse_count.value = 0
249
+ end
238
250
 
239
- @cipher.key = @key
251
+ ##
252
+ # @return [OpenSSL::Cipher]
253
+ def init_cipher
254
+ cipher = OpenSSL::Cipher.new(@algorithm)
240
255
 
241
- if !@iv.nil? and !@iv.empty? and @iv_random_length.nil?
242
- @cipher.iv = @iv if @iv
256
+ cipher.public_send(@mode)
243
257
 
244
- elsif !@iv_random_length.nil?
245
- @logger.debug("iv_random_length is configured, ignoring any statically defined value for 'iv'", :iv_random_length => @iv_random_length)
246
- else
247
- raise "cipher plugin: either 'iv' or 'iv_random_length' must be configured, but not both; aborting"
248
- end
258
+ cipher.key = @key.value
249
259
 
250
- @cipher.padding = @cipher_padding if @cipher_padding
260
+ cipher.padding = @cipher_padding if @cipher_padding
261
+
262
+ if @logger.trace?
263
+ @logger.trace("Cipher initialisation done", :mode => @mode,
264
+ :key => @key.value,
265
+ :iv_random_length => @iv_random_length,
266
+ :iv_random => @iv_random,
267
+ :cipher_padding => @cipher_padding)
268
+ end
251
269
 
252
- @logger.debug("Cipher initialisation done", :mode => @mode, :key => @key, :iv => @iv, :iv_random => @iv_random, :cipher_padding => @cipher_padding)
270
+ cipher
253
271
  end # def init_cipher
254
272
 
255
273
 
@@ -1,9 +1,9 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-cipher'
4
- s.version = '2.0.6'
4
+ s.version = '4.0.1'
5
5
  s.licenses = ['Apache License (2.0)']
6
- s.summary = "This filter parses a source and apply a cipher or decipher before storing it in the target"
6
+ s.summary = "Applies or removes a cipher to an event"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
8
8
  s.authors = ["Elastic"]
9
9
  s.email = 'info@elastic.co'
@@ -19,8 +19,10 @@ Gem::Specification.new do |s|
19
19
  # Special flag to let us know this is actually a logstash plugin
20
20
  s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
21
21
 
22
+
22
23
  # Gem dependencies
23
- s.add_runtime_dependency "logstash-core-plugin-api", "~> 1.0"
24
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
25
+ s.add_runtime_dependency "concurrent-ruby", '~> 1.0'
24
26
 
25
27
  s.add_development_dependency 'logstash-devutils'
26
28
  end
@@ -1,215 +1,144 @@
1
- # encoding: utf-8
1
+ # encoding: utf-8
2
+ require 'logstash-core'
3
+ require 'logstash/json'
4
+ require "logstash/codecs/base"
5
+ require 'logstash/filters/cipher'
2
6
 
3
- require "logstash/devutils/rspec/spec_helper"
4
- require 'logstash/filters/cipher'
7
+ describe LogStash::Filters::Cipher do
5
8
 
6
- describe LogStash::Filters::Cipher do
9
+ let(:cleartext) do
10
+ 'شسيبشن٤٤ت٥ت داھدساققبمر фывапролдзщшгнекутцйячсмить asdfghjklqpoiuztreyxcvbnm,.-öäü+ä123ß´yö.,;LÖÜ*O 來少精清皆人址法田手扌打表氵開日大木裝 1234567890#$%^&*()!@#;:\'?.>,<testAESEn+=_-~`}]'
11
+ end
7
12
 
8
- let(:cleartext) do
9
- 'شسيبشن٤٤ت٥ت داھدساققبمر фывапролдзщшгнекутцйячсмить asdfghjklqpoiuztreyxcvbnm,.-öäü+ä123ß´yö.,;LÖÜ*O 來少精清皆人址法田手扌打表氵開日大木裝 1234567890#$%^&*()!@#;:\'?.>,<testAESEn+=_-~`}]'
10
- end
13
+ describe 'single event, encrypt/decrypt aes-128-cbc, 16b RANDOM IV, 16b key, b64 encode' do
14
+ let(:event) do
15
+ LogStash::Event.new(LogStash::Json.load("{\"message\":\"#{cleartext}\"}"))
16
+ end
11
17
 
12
- let(:event) do
13
- "{\"message\":\"#{cleartext}\"}"
14
- end
18
+ let(:encrypter) do
19
+ described_class.new(
20
+ "algorithm" => "aes-128-cbc",
21
+ "cipher_padding" => 1,
22
+ "iv_random_length" => 16,
23
+ "key" => "1234567890123456",
24
+ "key_size" => 16,
25
+ "mode" => "encrypt",
26
+ "source" => "message",
27
+ "target" => "message_crypted",
28
+ "base64" => true,
29
+ "max_cipher_reuse" => 1)
30
+ end
15
31
 
16
- let(:pipeline) { LogStash::Pipeline.new(config) }
32
+ let(:decrypter) do
33
+ described_class.new(
34
+ "algorithm" => "aes-128-cbc",
35
+ "cipher_padding" => 1,
36
+ "iv_random_length" => 16,
37
+ "key" => "1234567890123456",
38
+ "key_size" => 16,
39
+ "mode" => "decrypt",
40
+ "source" => "message_crypted",
41
+ "target" => "message_decrypted",
42
+ "base64" => true,
43
+ "max_cipher_reuse" => 1)
44
+ end
17
45
 
18
- let(:events) do
19
- arr = event.is_a?(Array) ? event : [event]
20
- arr.map do |evt|
21
- LogStash::Event.new(evt.is_a?(String) ? LogStash::Json.load(evt) : evt)
22
- end
23
- end
46
+ before(:each) do
47
+ encrypter.register
48
+ decrypter.register
49
+ end
24
50
 
25
- let(:results) do
26
- pipeline.instance_eval { @filters.each(&:register) }
27
- results = []
28
- events.each do |evt|
29
- # filter call the block on all filtered events, included new events added by the filter
30
- pipeline.filter(evt) do |filtered_event|
31
- results.push(filtered_event)
32
- end
33
- end
34
- pipeline.flush_filters(:final => true) { |flushed_event| results << flushed_event }
35
-
36
- results.select { |e| !e.cancelled? }
37
- end
51
+ let(:result) do
52
+ encrypter.filter(event)
53
+ decrypter.filter(event)
54
+ event
55
+ end
38
56
 
39
- describe 'single event, encrypt/decrypt aes-128-cbc, 16b RANDOM IV, 16b key, b64 encode' do
40
-
41
- let(:config) do
42
- <<-CONFIG
43
- filter {
44
-
45
- cipher {
46
- algorithm => "aes-128-cbc"
47
- cipher_padding => 1
48
- iv_random_length => 16
49
- key => "1234567890123456"
50
- key_size => 16
51
- mode => "encrypt"
52
- source => "message"
53
- target => "message_crypted"
54
- base64 => true
55
- max_cipher_reuse => 1
56
- }
57
-
58
- cipher {
59
- algorithm => "aes-128-cbc"
60
- cipher_padding => 1
61
- iv_random_length => 16
62
- key => "1234567890123456"
63
- key_size => 16
64
- mode => "decrypt"
65
- source => "message_crypted"
66
- target => "message_decrypted"
67
- base64 => true
68
- max_cipher_reuse => 1
69
- }
70
- }
71
- CONFIG
72
- end
73
-
74
- it 'validate initial cleartext message' do
75
- result = results.first
76
- expect(result["message"]).to eq(cleartext)
77
- end
78
-
79
- it 'validate decrypted message' do
80
- result = results.first
81
- expect(result["message_decrypted"]).to eq(result["message"])
82
- end
83
-
84
- it 'validate encrypted message is not equal to message' do
85
- result = results.first
86
- expect(result["message"]).not_to eq(result["message_crypted"])
87
- end
57
+ it 'validate initial cleartext message' do
58
+ expect(result.get("message")).to eq(cleartext)
59
+ end
88
60
 
89
- end
61
+ it 'validate decrypted message' do
62
+ expect(result.get("message_decrypted")).to eq(result.get("message"))
63
+ end
64
+
65
+ it 'validate encrypted message is not equal to message' do
66
+ expect(result.get("message")).not_to eq(result.get("message_crypted"))
67
+ end
68
+
69
+ end
90
70
 
71
+ describe '1000 events, 11 re-use, encrypt/decrypt aes-128-cbc, 16b RANDOM IV, 16b key, b64 encode' do
91
72
 
92
- describe 'single event, encrypt/decrypt aes-128-cbc, 16b STATIC IV, 16b key, b64 encode' do
93
-
94
- let(:config) do
95
- <<-CONFIG
96
- filter {
97
-
98
- cipher {
99
- algorithm => "aes-128-cbc"
100
- cipher_padding => 1
101
- iv => "1234567890123456"
102
- key => "1234567890123456"
103
- key_size => 16
104
- mode => "encrypt"
105
- source => "message"
106
- target => "message_crypted"
107
- base64 => true
108
- max_cipher_reuse => 1
109
- }
110
-
111
- cipher {
112
- algorithm => "aes-128-cbc"
113
- cipher_padding => 1
114
- iv => "1234567890123456"
115
- key => "1234567890123456"
116
- key_size => 16
117
- mode => "decrypt"
118
- source => "message_crypted"
119
- target => "message_decrypted"
120
- base64 => true
121
- max_cipher_reuse => 1
122
- }
123
- }
124
- CONFIG
125
- end
126
-
127
- it 'validate initial cleartext message' do
128
- result = results.first
129
- expect(result["message"]).to eq(cleartext)
130
- end
131
-
132
- it 'validate decrypted message' do
133
- result = results.first
134
- expect(result["message_decrypted"]).to eq(result["message"])
135
- end
136
-
137
- it 'validate encrypted message is not equal to message' do
138
- result = results.first
139
- expect(result["message"]).not_to eq(result["message_crypted"])
140
- end
73
+ total_events = 1000
141
74
 
75
+ let(:events) do
76
+ (1..total_events).map do |i|
77
+ LogStash::Event.new(LogStash::Json.load("{\"message\":\"#{cleartext}\"}"))
142
78
  end
79
+ end
80
+
81
+ let(:encrypter) do
82
+ described_class.new(
83
+ "algorithm" => "aes-128-cbc",
84
+ "cipher_padding" => 1,
85
+ "iv_random_length" => 16,
86
+ "key" => "1234567890123456",
87
+ "key_size" => 16,
88
+ "mode" => "encrypt",
89
+ "source" => "message",
90
+ "target" => "message_crypted",
91
+ "base64" => true,
92
+ "max_cipher_reuse" => 11)
93
+ end
94
+
95
+ let(:decrypter) do
96
+ described_class.new(
97
+ "algorithm" => "aes-128-cbc",
98
+ "cipher_padding" => 1,
99
+ "iv_random_length" => 16,
100
+ "key" => "1234567890123456",
101
+ "key_size" => 16,
102
+ "mode" => "decrypt",
103
+ "source" => "message_crypted",
104
+ "target" => "message_decrypted",
105
+ "base64" => true,
106
+ "max_cipher_reuse" => 11)
107
+ end
108
+
109
+ before(:each) do
110
+ encrypter.register
111
+ decrypter.register
112
+ end
143
113
 
114
+ let(:results) do
115
+ events.each do |e|
116
+ encrypter.filter(e)
117
+ decrypter.filter(e)
118
+ end
119
+ events
120
+ end
144
121
 
145
- describe '1000 events, 11 re-use, encrypt/decrypt aes-128-cbc, 16b RANDOM IV, 16b key, b64 encode' do
146
-
147
- total_events = 1000
148
-
149
- let(:event) do
150
- events = []
151
- (1..total_events).each do |i|
152
- events.push("{\"message\":\"#{cleartext}\"}")
153
- end
154
- return events
155
- end
156
-
157
- let(:config) do
158
- <<-CONFIG
159
- filter {
160
-
161
- cipher {
162
- algorithm => "aes-128-cbc"
163
- cipher_padding => 1
164
- iv_random_length => 16
165
- key => "1234567890123456"
166
- key_size => 16
167
- mode => "encrypt"
168
- source => "message"
169
- target => "message_crypted"
170
- base64 => true
171
- max_cipher_reuse => 11
172
- }
173
-
174
- cipher {
175
- algorithm => "aes-128-cbc"
176
- cipher_padding => 1
177
- iv_random_length => 16
178
- key => "1234567890123456"
179
- key_size => 16
180
- mode => "decrypt"
181
- source => "message_crypted"
182
- target => "message_decrypted"
183
- base64 => true
184
- max_cipher_reuse => 11
185
- }
186
- }
187
- CONFIG
188
- end
189
-
190
- it 'validate total events' do
191
- expect(results.length).to eq(total_events)
192
- end
193
-
194
- it 'validate initial cleartext message' do
195
- results.each do |result|
196
- expect(result["message"]).to eq(cleartext)
197
- end
198
- end
199
-
200
- it 'validate decrypted message' do
201
- results.each do |result|
202
- expect(result["message_decrypted"]).to eq(result["message"])
203
- end
204
- end
205
-
206
- it 'validate encrypted message is not equal to message' do
207
- results.each do |result|
208
- expect(result["message"]).not_to eq(result["message_crypted"])
209
- end
210
- end
122
+ it 'validate total events' do
123
+ expect(results.length).to eq(total_events)
124
+ end
211
125
 
126
+ it 'validate initial cleartext message' do
127
+ results.each do |result|
128
+ expect(result.get("message")).to eq(cleartext)
212
129
  end
130
+ end
213
131
 
132
+ it 'validate decrypted message' do
133
+ results.each do |result|
134
+ expect(result.get("message_decrypted")).to eq(result.get("message"))
135
+ end
214
136
  end
215
137
 
138
+ it 'validate encrypted message is not equal to message' do
139
+ results.each do |result|
140
+ expect(result.get("message")).not_to eq(result.get("message_crypted"))
141
+ end
142
+ end
143
+ end
144
+ end
metadata CHANGED
@@ -1,22 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-cipher
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.6
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-23 00:00:00.000000000 Z
11
+ date: 2020-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.60'
19
+ - - "<="
20
+ - !ruby/object:Gem::Version
21
+ version: '2.99'
22
+ name: logstash-core-plugin-api
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.60'
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.99'
13
33
  - !ruby/object:Gem::Dependency
14
34
  requirement: !ruby/object:Gem::Requirement
15
35
  requirements:
16
36
  - - "~>"
17
37
  - !ruby/object:Gem::Version
18
38
  version: '1.0'
19
- name: logstash-core-plugin-api
39
+ name: concurrent-ruby
20
40
  prerelease: false
21
41
  type: :runtime
22
42
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,7 +58,9 @@ dependencies:
38
58
  - - ">="
39
59
  - !ruby/object:Gem::Version
40
60
  version: '0'
41
- description: This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program
61
+ description: This gem is a Logstash plugin required to be installed on top of the
62
+ Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
63
+ gem is not a stand-alone program
42
64
  email: info@elastic.co
43
65
  executables: []
44
66
  extensions: []
@@ -76,9 +98,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
98
  version: '0'
77
99
  requirements: []
78
100
  rubyforge_project:
79
- rubygems_version: 2.4.8
101
+ rubygems_version: 2.6.13
80
102
  signing_key:
81
103
  specification_version: 4
82
- summary: This filter parses a source and apply a cipher or decipher before storing it in the target
104
+ summary: Applies or removes a cipher to an event
83
105
  test_files:
84
106
  - spec/filters/cipher_spec.rb