xxtea 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +46 -19
- data/ext/xxtea/xxtea.c +193 -20
- data/lib/xxtea/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 89a73616644886a2d6c15b0567b6a123ba8029a410affd9aa7c76213358ba5b9
|
|
4
|
+
data.tar.gz: 181fff72b4214e44978ccd5ad26209d1362b0dcccaa949944bcf8e29c14b3577
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5dc86b066d959b3d9bbb013fa9f3ba7cd772608cc5dcb434889185c8a0fccb4ab0b01f210fa3c628745d6efd9e760a29e175d469febb2d4618d61e62e13b0ad8
|
|
7
|
+
data.tar.gz: 804d0e50a19dcfcfbfb087376612e4d7f92309b9192463e324b92e133cf291466f0812127b6dabe22927bb48bb160032290beea8e596f3be4b66f25374c2c42e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
- Add the `:length_word_suffix` and `:length_word_prefix` padding schemes, matching all five padding modes of [Python xxtea](https://github.com/ifduyue/xxtea) 6.2.0.
|
|
6
|
+
- `:length_word_suffix`: zero-pads to a 4-byte boundary, then appends one little-endian `uint32` with the original length (Cocos Creator JSC files).
|
|
7
|
+
- `:length_word_prefix`: prepends one little-endian `uint32` with the original length, then zero-pads the data to a 4-byte boundary.
|
|
8
|
+
- Both support empty input (padded to XXTEA's 2-word minimum) and raise `ArgumentError` on decrypt when the zero padding or length word is inconsistent.
|
|
9
|
+
- Add `XXTEA::LENGTH_WORD_SUFFIX` and `XXTEA::LENGTH_WORD_PREFIX` constant aliases.
|
|
10
|
+
|
|
11
|
+
## 1.1.0
|
|
12
|
+
|
|
13
|
+
- Add named padding schemes: `:pkcs7_4_min8` (default, also `true`), `:pkcs7_8`, and `:none` (also `false`).
|
|
14
|
+
- `:pkcs7_4_min8` is 4-byte PKCS#7-like with an 8-byte minimum (pad values 5–8 for short inputs), compatible with Python xxtea.
|
|
15
|
+
- `:pkcs7_8` is standard 8-byte PKCS#7, compatible with Python [xxteang](https://github.com/ifduyue/xxteang).
|
|
16
|
+
|
|
3
17
|
## 1.0.0
|
|
4
18
|
|
|
5
19
|
- Rewrite as a Ruby C extension compatible with Python [xxtea](https://github.com/ifduyue/xxtea) 5.3.3.
|
data/README.md
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
[XXTEA](https://en.wikipedia.org/wiki/XXTEA) implemented as a Ruby C extension, licensed under 2-clause BSD.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Default ciphertext is compatible with the [Python xxtea](https://github.com/ifduyue/xxtea) package.
|
|
9
|
+
`padding: :pkcs7_8` is compatible with [Python xxteang](https://github.com/ifduyue/xxteang).
|
|
9
10
|
|
|
10
11
|
The XXTEA algorithm takes a 128-bit key and operates on an array of 32-bit
|
|
11
12
|
integers (at least 2 integers), but it doesn't define the conversions between
|
|
@@ -21,12 +22,11 @@ integers, which is required by the XXTEA algorithm). As a result of these
|
|
|
21
22
|
measures, you can encrypt not only texts, but also any binary bytes of any
|
|
22
23
|
length.
|
|
23
24
|
|
|
24
|
-
> **Note:**
|
|
25
|
-
>
|
|
26
|
-
>
|
|
27
|
-
>
|
|
28
|
-
>
|
|
29
|
-
> for raw XXTEA (requires data length ≥ 8 and multiple of 4).
|
|
25
|
+
> **Note:** The default (`:pkcs7_4_min8`) is **not** standard 4-byte PKCS#7.
|
|
26
|
+
> For inputs shorter than 4 bytes it pads an extra 4 bytes (pad values 5–8)
|
|
27
|
+
> to satisfy XXTEA's 2-word minimum. Pass `padding: :pkcs7_8` for standard
|
|
28
|
+
> 8-byte PKCS#7 (compatible with Python xxteang), or `padding: false` for
|
|
29
|
+
> raw XXTEA (requires data length ≥ 8 and multiple of 4).
|
|
30
30
|
|
|
31
31
|
## Installation
|
|
32
32
|
|
|
@@ -87,9 +87,11 @@ They are stored on the object and used by every `encrypt`, `decrypt`,
|
|
|
87
87
|
`encrypt_hex`, and `decrypt_hex` call:
|
|
88
88
|
|
|
89
89
|
```ruby
|
|
90
|
-
c = XXTEA.new(key)
|
|
91
|
-
c = XXTEA.new(key, rounds: 64)
|
|
92
|
-
c = XXTEA.new(key, padding: false)
|
|
90
|
+
c = XXTEA.new(key) # rounds=0, padding=:pkcs7_4_min8
|
|
91
|
+
c = XXTEA.new(key, rounds: 64) # override rounds
|
|
92
|
+
c = XXTEA.new(key, padding: false) # disable padding
|
|
93
|
+
c = XXTEA.new(key, padding: :pkcs7_8) # 8-byte PKCS#7
|
|
94
|
+
c = XXTEA.new(key, padding: :length_word_suffix) # length word + zero padding
|
|
93
95
|
c = XXTEA.new(key, padding: false, rounds: 42)
|
|
94
96
|
```
|
|
95
97
|
|
|
@@ -103,19 +105,43 @@ s == XXTEA.decrypt([hexenc].pack("H*"), key) # => true
|
|
|
103
105
|
|
|
104
106
|
## Padding
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
scheme. The pad byte value is `4 - (data.bytesize & 3)` (range 1–4), plus an
|
|
108
|
-
extra 4 bytes when the input is shorter than 4 bytes to meet XXTEA's 2-word
|
|
109
|
-
minimum (producing pad values 5–8).
|
|
108
|
+
`padding` accepts a scheme name, so more paddings can be added later:
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
| Value | Meaning |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `true` or `:pkcs7_4_min8` (default) | 4-byte PKCS#7-like, padded to at least 8 bytes. Compatible with Python xxtea. Not standard 4-byte PKCS#7 |
|
|
113
|
+
| `:pkcs7_8` | Standard **8-byte** PKCS#7, compatible with Python xxteang |
|
|
114
|
+
| `:length_word_suffix` | Zero-pad to a 4-byte boundary, then append one little-endian `uint32` with the original length. Cocos Creator JSC files using this layout can be decrypted. Compatible with Python xxtea 6.2.0 |
|
|
115
|
+
| `:length_word_prefix` | Prepend one little-endian `uint32` with the original length, then zero-pad the data to a 4-byte boundary. Compatible with Python xxtea 6.2.0 |
|
|
116
|
+
| `false` or `:none` | No padding (raw XXTEA) |
|
|
117
|
+
|
|
118
|
+
`XXTEA::PKCS7_4_MIN8`, `XXTEA::PKCS7_8`, `XXTEA::LENGTH_WORD_PREFIX`, and
|
|
119
|
+
`XXTEA::LENGTH_WORD_SUFFIX` are aliases for the symbols.
|
|
120
|
+
|
|
121
|
+
The default `:pkcs7_4_min8` scheme uses pad byte value `4 - (data.bytesize & 3)`
|
|
122
|
+
(range 1–4), plus an extra 4 bytes when the input is shorter than 4 bytes
|
|
123
|
+
to meet XXTEA's 2-word minimum (producing pad values 5–8). Standard 4-byte
|
|
124
|
+
PKCS#7 never uses pad values 5–8. Because padding always adds at least one
|
|
125
|
+
byte, encrypting an 8-byte input produces a 12-byte ciphertext.
|
|
126
|
+
|
|
127
|
+
8-byte PKCS#7 uses pad byte value `8 - (data.bytesize & 7)` (range 1–8).
|
|
128
|
+
Encrypting an 8-byte input produces a 16-byte ciphertext.
|
|
129
|
+
|
|
130
|
+
The length-word schemes store the original byte length in a little-endian
|
|
131
|
+
`uint32` word, so the plaintext length must fit in 32 bits (`RangeError`
|
|
132
|
+
otherwise). The data is zero-padded to a 4-byte boundary around that word:
|
|
133
|
+
the length word is the last word for `:length_word_suffix` and the first
|
|
134
|
+
word for `:length_word_prefix`. Because of XXTEA's 2-word minimum, empty
|
|
135
|
+
input produces an 8-byte ciphertext in either scheme.
|
|
115
136
|
|
|
116
137
|
```ruby
|
|
117
138
|
XXTEA.decrypt_hex(XXTEA.encrypt_hex("", key), key) # => ""
|
|
118
139
|
XXTEA.decrypt_hex(XXTEA.encrypt_hex(" ", key), key) # => " "
|
|
140
|
+
|
|
141
|
+
XXTEA.encrypt("12345678", key).bytesize # => 12 (:pkcs7_4_min8)
|
|
142
|
+
XXTEA.encrypt("12345678", key, padding: :pkcs7_8).bytesize # => 16 (:pkcs7_8)
|
|
143
|
+
XXTEA.encrypt("12345678", key, padding: :length_word_suffix).bytesize # => 12
|
|
144
|
+
XXTEA.encrypt("12345678", key, padding: :length_word_prefix).bytesize # => 12
|
|
119
145
|
```
|
|
120
146
|
|
|
121
147
|
You can disable padding by setting `padding: false`.
|
|
@@ -196,7 +222,8 @@ XXTEA.new("k" * 16, rounds: 2**32)
|
|
|
196
222
|
|
|
197
223
|
## Compatibility
|
|
198
224
|
|
|
199
|
-
- Compatible with [Python xxtea](https://github.com/ifduyue/xxtea) (
|
|
225
|
+
- Compatible with [Python xxtea](https://github.com/ifduyue/xxtea) 6.2.0: all five padding schemes (`:pkcs7_4_min8`, `:pkcs7_8`, `:length_word_prefix`, `:length_word_suffix`, `:none`), endianness, and rounds.
|
|
226
|
+
- `padding: :pkcs7_8` is compatible with [Python xxteang](https://github.com/ifduyue/xxteang).
|
|
200
227
|
- The `XXTEA.encrypt(data, key)` / `XXTEA.decrypt(data, key)` class methods remain compatible with gem 0.0.1 for valid ciphertext. `XXTEA` is now a class rather than a module, and invalid padding raises `ArgumentError` instead of returning stripped bytes.
|
|
201
228
|
|
|
202
229
|
## Releasing
|
data/ext/xxtea/xxtea.c
CHANGED
|
@@ -22,9 +22,13 @@
|
|
|
22
22
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
23
23
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
25
|
+
* Default ciphertext is compatible with the Python xxtea package
|
|
26
26
|
* (https://github.com/ifduyue/xxtea): little-endian 32-bit words and
|
|
27
|
-
*
|
|
27
|
+
* :pkcs7_4_min8 padding (4-byte PKCS#7-like, pad+4 for inputs shorter than 4 bytes).
|
|
28
|
+
* padding: :pkcs7_8 uses 8-byte PKCS#7, compatible with Python xxteang
|
|
29
|
+
* (https://github.com/ifduyue/xxteang); :length_word_prefix and
|
|
30
|
+
* :length_word_suffix prepend/append a little-endian uint32 length word
|
|
31
|
+
* with zero padding, matching Python xxtea 6.2.0.
|
|
28
32
|
*/
|
|
29
33
|
|
|
30
34
|
#include "ruby.h"
|
|
@@ -45,6 +49,11 @@
|
|
|
45
49
|
|
|
46
50
|
static ID id_padding;
|
|
47
51
|
static ID id_rounds;
|
|
52
|
+
static ID id_none;
|
|
53
|
+
static ID id_pkcs7_4_min8;
|
|
54
|
+
static ID id_pkcs7_8;
|
|
55
|
+
static ID id_length_word_prefix;
|
|
56
|
+
static ID id_length_word_suffix;
|
|
48
57
|
static VALUE cXXTEA;
|
|
49
58
|
|
|
50
59
|
typedef struct {
|
|
@@ -122,36 +131,84 @@ bytes2longs(const char *in, long inlen, uint32_t *out, int padding)
|
|
|
122
131
|
long i, nwords;
|
|
123
132
|
int pad;
|
|
124
133
|
const unsigned char *s = (const unsigned char *)in;
|
|
134
|
+
uint32_t *dst = out;
|
|
135
|
+
|
|
136
|
+
if (padding == 2) {
|
|
137
|
+
/* uint32 store, not memcpy(&inlen): 64-bit would copy the high half. */
|
|
138
|
+
out[0] = (uint32_t)inlen;
|
|
139
|
+
dst = out + 1;
|
|
140
|
+
}
|
|
125
141
|
|
|
126
142
|
nwords = inlen >> 2;
|
|
127
143
|
for (i = 0; i < nwords; i++) {
|
|
128
144
|
#if XXTEA_LITTLE_ENDIAN
|
|
129
|
-
memcpy(&
|
|
145
|
+
memcpy(&dst[i], s + 4 * i, 4);
|
|
130
146
|
#else
|
|
131
147
|
const unsigned char *p = s + 4 * i;
|
|
132
|
-
|
|
148
|
+
dst[i] = (uint32_t)p[0] | ((uint32_t)p[1] << 8) |
|
|
133
149
|
((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
|
|
134
150
|
#endif
|
|
135
151
|
}
|
|
136
152
|
|
|
153
|
+
i = nwords << 2;
|
|
154
|
+
|
|
155
|
+
if (padding == 1 || padding == 2) {
|
|
156
|
+
/* XXTEA needs two words, so empty input gets an extra zero word. */
|
|
157
|
+
uint32_t w = 0;
|
|
158
|
+
int shift = 0;
|
|
159
|
+
for (; i < inlen; i++, shift += 8) {
|
|
160
|
+
w |= (uint32_t)s[i] << shift;
|
|
161
|
+
}
|
|
162
|
+
if ((inlen & 3) != 0) {
|
|
163
|
+
dst[nwords] = w;
|
|
164
|
+
nwords++;
|
|
165
|
+
}
|
|
166
|
+
if (nwords < 1) {
|
|
167
|
+
dst[nwords++] = 0;
|
|
168
|
+
}
|
|
169
|
+
if (padding == 1) {
|
|
170
|
+
dst[nwords] = (uint32_t)inlen;
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (padding == 8) {
|
|
176
|
+
/*
|
|
177
|
+
* 8-byte PKCS#7 (xxteang): pad = 8 - (len & 7), range 1-8.
|
|
178
|
+
* Completes the partial word, then adds a whole extra pad word
|
|
179
|
+
* unless the length is 4 mod 8.
|
|
180
|
+
*/
|
|
181
|
+
uint32_t w = 0;
|
|
182
|
+
int r = (int)(inlen & 3);
|
|
183
|
+
int shift = 0;
|
|
184
|
+
uint32_t pw;
|
|
185
|
+
for (; i < inlen; i++, shift += 8) {
|
|
186
|
+
w |= (uint32_t)s[i] << shift;
|
|
187
|
+
}
|
|
188
|
+
pad = 8 - (int)(inlen & 7);
|
|
189
|
+
pw = (uint32_t)pad * 0x01010101u;
|
|
190
|
+
w |= pw & (~0u << (8 * r));
|
|
191
|
+
out[nwords] = w;
|
|
192
|
+
if ((inlen & 4) == 0) {
|
|
193
|
+
out[nwords + 1] = pw;
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
137
198
|
/*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* to zero the buffer first. Inputs shorter than 4 bytes are padded
|
|
142
|
-
* to two words, which also guarantees the minimum XXTEA block size.
|
|
199
|
+
* :pkcs7_4_min8 (default): 4-byte PKCS#7-like, but inputs shorter
|
|
200
|
+
* than 4 bytes are padded to two words (pad values 5-8) for XXTEA's
|
|
201
|
+
* 2-word minimum. Not standard PKCS#7.
|
|
143
202
|
*/
|
|
144
|
-
|
|
145
|
-
if (padding || (inlen & 3) != 0) {
|
|
203
|
+
if (padding == 4 || (inlen & 3) != 0) {
|
|
146
204
|
uint32_t w = 0;
|
|
147
205
|
int r = (int)(inlen & 3);
|
|
148
206
|
int shift = 0;
|
|
149
207
|
for (; i < inlen; i++, shift += 8) {
|
|
150
208
|
w |= (uint32_t)s[i] << shift;
|
|
151
209
|
}
|
|
152
|
-
if (padding) {
|
|
210
|
+
if (padding == 4) {
|
|
153
211
|
pad = 4 - r;
|
|
154
|
-
/* Ensure XXTEA always has at least two 32-bit words. */
|
|
155
212
|
if (inlen < 4) {
|
|
156
213
|
pad += 4;
|
|
157
214
|
}
|
|
@@ -190,8 +247,41 @@ longs2bytes(const uint32_t *in, long inlen, char *out, int padding)
|
|
|
190
247
|
|
|
191
248
|
outlen = inlen * 4;
|
|
192
249
|
|
|
193
|
-
|
|
194
|
-
|
|
250
|
+
if (padding == 1 || padding == 2) {
|
|
251
|
+
int prefix = padding == 2;
|
|
252
|
+
long n = outlen - 4;
|
|
253
|
+
long leftover, pad_from, pad_to;
|
|
254
|
+
uint32_t m32;
|
|
255
|
+
if (prefix) {
|
|
256
|
+
m32 = (uint32_t)s[0] | ((uint32_t)s[1] << 8) |
|
|
257
|
+
((uint32_t)s[2] << 16) | ((uint32_t)s[3] << 24);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
m32 = (uint32_t)s[n] | ((uint32_t)s[n + 1] << 8) |
|
|
261
|
+
((uint32_t)s[n + 2] << 16) | ((uint32_t)s[n + 3] << 24);
|
|
262
|
+
}
|
|
263
|
+
if ((size_t)m32 > (size_t)n) {
|
|
264
|
+
return -1;
|
|
265
|
+
}
|
|
266
|
+
leftover = n - (long)m32;
|
|
267
|
+
pad_from = prefix ? 4 + (long)m32 : (long)m32;
|
|
268
|
+
pad_to = prefix ? outlen : n;
|
|
269
|
+
/* leftover 4 is the empty 2-word case; otherwise 0-3 zero-pad bytes. */
|
|
270
|
+
if (leftover > 3 && !(m32 == 0 && leftover == 4)) {
|
|
271
|
+
return -1;
|
|
272
|
+
}
|
|
273
|
+
for (i = pad_from; i < pad_to; i++) {
|
|
274
|
+
if (s[i] != 0) {
|
|
275
|
+
return -1;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (prefix && m32 != 0) {
|
|
279
|
+
memmove(s, s + 4, (size_t)m32);
|
|
280
|
+
}
|
|
281
|
+
outlen = (long)m32;
|
|
282
|
+
}
|
|
283
|
+
/* PKCS#7-style unpadding (4-byte or 8-byte; pad values 1-8). */
|
|
284
|
+
else if (padding) {
|
|
195
285
|
pad = s[outlen - 1];
|
|
196
286
|
outlen -= pad;
|
|
197
287
|
|
|
@@ -266,13 +356,56 @@ parse_rounds(VALUE obj)
|
|
|
266
356
|
return NUM2UINT(obj);
|
|
267
357
|
}
|
|
268
358
|
|
|
359
|
+
/* 0 = none, 1 = :length_word_suffix, 2 = :length_word_prefix,
|
|
360
|
+
* 4 = :pkcs7_4_min8 (default), 8 = :pkcs7_8. */
|
|
361
|
+
static int
|
|
362
|
+
parse_padding(VALUE obj)
|
|
363
|
+
{
|
|
364
|
+
ID id;
|
|
365
|
+
|
|
366
|
+
if (obj == Qfalse) {
|
|
367
|
+
return 0;
|
|
368
|
+
}
|
|
369
|
+
if (obj == Qtrue) {
|
|
370
|
+
return 4;
|
|
371
|
+
}
|
|
372
|
+
if (RB_TYPE_P(obj, T_STRING)) {
|
|
373
|
+
obj = rb_str_intern(obj);
|
|
374
|
+
}
|
|
375
|
+
if (!SYMBOL_P(obj)) {
|
|
376
|
+
rb_raise(rb_eTypeError,
|
|
377
|
+
"padding must be true, false, :none, :pkcs7_4_min8, "
|
|
378
|
+
":pkcs7_8, :length_word_prefix, or :length_word_suffix");
|
|
379
|
+
}
|
|
380
|
+
id = SYM2ID(obj);
|
|
381
|
+
if (id == id_none) {
|
|
382
|
+
return 0;
|
|
383
|
+
}
|
|
384
|
+
if (id == id_length_word_suffix) {
|
|
385
|
+
return 1;
|
|
386
|
+
}
|
|
387
|
+
if (id == id_length_word_prefix) {
|
|
388
|
+
return 2;
|
|
389
|
+
}
|
|
390
|
+
if (id == id_pkcs7_4_min8) {
|
|
391
|
+
return 4;
|
|
392
|
+
}
|
|
393
|
+
if (id == id_pkcs7_8) {
|
|
394
|
+
return 8;
|
|
395
|
+
}
|
|
396
|
+
rb_raise(rb_eArgError,
|
|
397
|
+
"unknown padding %+"PRIsVALUE" (expected :none, :pkcs7_4_min8, "
|
|
398
|
+
":pkcs7_8, :length_word_prefix, or :length_word_suffix)",
|
|
399
|
+
obj);
|
|
400
|
+
}
|
|
401
|
+
|
|
269
402
|
static void
|
|
270
403
|
parse_opts(VALUE opts, int *padding, unsigned int *rounds)
|
|
271
404
|
{
|
|
272
405
|
ID kwids[2];
|
|
273
406
|
VALUE kwvals[2];
|
|
274
407
|
|
|
275
|
-
*padding =
|
|
408
|
+
*padding = 4;
|
|
276
409
|
*rounds = 0;
|
|
277
410
|
if (NIL_P(opts)) {
|
|
278
411
|
return;
|
|
@@ -283,7 +416,7 @@ parse_opts(VALUE opts, int *padding, unsigned int *rounds)
|
|
|
283
416
|
rb_get_kwargs(opts, kwids, 0, 2, kwvals);
|
|
284
417
|
|
|
285
418
|
if (kwvals[0] != Qundef) {
|
|
286
|
-
*padding =
|
|
419
|
+
*padding = parse_padding(kwvals[0]);
|
|
287
420
|
}
|
|
288
421
|
if (kwvals[1] != Qundef) {
|
|
289
422
|
*rounds = parse_rounds(kwvals[1]);
|
|
@@ -315,7 +448,33 @@ encrypt_impl(VALUE data, const char key[16], int padding, unsigned int rounds)
|
|
|
315
448
|
"Data length must be a multiple of 4 bytes and must not be less than 8 bytes");
|
|
316
449
|
}
|
|
317
450
|
|
|
318
|
-
|
|
451
|
+
if (padding == 8) {
|
|
452
|
+
if (data_len > LONG_MAX - 8) {
|
|
453
|
+
rb_raise(rb_eRangeError, "data too large");
|
|
454
|
+
}
|
|
455
|
+
alen = ((data_len & ~7L) + 8) >> 2;
|
|
456
|
+
}
|
|
457
|
+
else if (padding == 4) {
|
|
458
|
+
alen = data_len < 4 ? 2 : (data_len >> 2) + 1;
|
|
459
|
+
}
|
|
460
|
+
else if (padding == 1 || padding == 2) {
|
|
461
|
+
/* The length word is a uint32, so the plaintext length must fit. */
|
|
462
|
+
#if LONG_MAX > 2147483647L
|
|
463
|
+
if (data_len > 0xFFFFFFFFL) {
|
|
464
|
+
rb_raise(rb_eRangeError, "data too large");
|
|
465
|
+
}
|
|
466
|
+
#endif
|
|
467
|
+
if (data_len > LONG_MAX - 4) {
|
|
468
|
+
rb_raise(rb_eRangeError, "data too large");
|
|
469
|
+
}
|
|
470
|
+
alen = (data_len >> 2) + ((data_len & 3) != 0 ? 1 : 0) + 1;
|
|
471
|
+
if (alen < 2) {
|
|
472
|
+
alen = 2;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
alen = data_len >> 2;
|
|
477
|
+
}
|
|
319
478
|
if (alen > INT_MAX || alen > LONG_MAX / 4) {
|
|
320
479
|
rb_raise(rb_eRangeError, "data too large");
|
|
321
480
|
}
|
|
@@ -501,7 +660,7 @@ xxtea_alloc(VALUE klass)
|
|
|
501
660
|
xxtea_cipher_t *cipher;
|
|
502
661
|
VALUE obj = TypedData_Make_Struct(klass, xxtea_cipher_t, &xxtea_cipher_type, cipher);
|
|
503
662
|
memset(cipher, 0, sizeof(*cipher));
|
|
504
|
-
cipher->padding =
|
|
663
|
+
cipher->padding = 4;
|
|
505
664
|
cipher->rounds = 0;
|
|
506
665
|
return obj;
|
|
507
666
|
}
|
|
@@ -556,7 +715,11 @@ xxtea_inspect(VALUE self)
|
|
|
556
715
|
xxtea_cipher_t *cipher = xxtea_get(self);
|
|
557
716
|
return rb_sprintf("#<%s:%p padding=%s rounds=%u>",
|
|
558
717
|
rb_obj_classname(self), (void *)self,
|
|
559
|
-
cipher->padding
|
|
718
|
+
cipher->padding == 0 ? "false" :
|
|
719
|
+
cipher->padding == 1 ? "length_word_suffix" :
|
|
720
|
+
cipher->padding == 2 ? "length_word_prefix" :
|
|
721
|
+
cipher->padding == 4 ? "pkcs7_4_min8" : "pkcs7_8",
|
|
722
|
+
cipher->rounds);
|
|
560
723
|
}
|
|
561
724
|
|
|
562
725
|
void
|
|
@@ -566,6 +729,11 @@ Init_xxtea(void)
|
|
|
566
729
|
|
|
567
730
|
id_padding = rb_intern("padding");
|
|
568
731
|
id_rounds = rb_intern("rounds");
|
|
732
|
+
id_none = rb_intern("none");
|
|
733
|
+
id_pkcs7_4_min8 = rb_intern("pkcs7_4_min8");
|
|
734
|
+
id_pkcs7_8 = rb_intern("pkcs7_8");
|
|
735
|
+
id_length_word_prefix = rb_intern("length_word_prefix");
|
|
736
|
+
id_length_word_suffix = rb_intern("length_word_suffix");
|
|
569
737
|
|
|
570
738
|
cXXTEA = rb_define_class("XXTEA", rb_cObject);
|
|
571
739
|
rb_define_alloc_func(cXXTEA, xxtea_alloc);
|
|
@@ -581,4 +749,9 @@ Init_xxtea(void)
|
|
|
581
749
|
rb_define_method(cXXTEA, "encrypt_hex", xxtea_encrypt_hex, 1);
|
|
582
750
|
rb_define_method(cXXTEA, "decrypt_hex", xxtea_decrypt_hex, 1);
|
|
583
751
|
rb_define_method(cXXTEA, "inspect", xxtea_inspect, 0);
|
|
752
|
+
|
|
753
|
+
rb_define_const(cXXTEA, "PKCS7_4_MIN8", ID2SYM(id_pkcs7_4_min8));
|
|
754
|
+
rb_define_const(cXXTEA, "PKCS7_8", ID2SYM(id_pkcs7_8));
|
|
755
|
+
rb_define_const(cXXTEA, "LENGTH_WORD_PREFIX", ID2SYM(id_length_word_prefix));
|
|
756
|
+
rb_define_const(cXXTEA, "LENGTH_WORD_SUFFIX", ID2SYM(id_length_word_suffix));
|
|
584
757
|
}
|
data/lib/xxtea/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xxtea
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yue Du
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |
|
|
14
14
|
XXTEA implemented as a Ruby C extension. Ciphertext is compatible with the
|