react-native-des-machine 0.1.0 → 1.0.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.
- package/README.md +272 -49
- package/android/src/main/java/com/desmachine/DesMachineModule.kt +77 -68
- package/ios/DesMachine.h +0 -6
- package/ios/DesMachine.mm +120 -83
- package/lib/module/NativeDesMachine.js.map +1 -1
- package/lib/module/index.js +149 -11
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeDesMachine.d.ts +25 -3
- package/lib/typescript/src/NativeDesMachine.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +95 -5
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +27 -11
- package/src/NativeDesMachine.ts +26 -3
- package/src/index.ts +164 -13
package/README.md
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
# react-native-des-machine
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/react-native-des-machine)
|
|
4
|
+
[](https://www.npmjs.com/package/react-native-des-machine)
|
|
5
|
+
[](https://github.com/NeRo8/react-native-des-machine/blob/main/LICENSE)
|
|
6
|
+
[](https://reactnative.dev/)
|
|
7
|
+
|
|
3
8
|
A React Native TurboModule that provides DES (Data Encryption Standard) encryption and decryption with support for multiple cipher modes, padding schemes, and output formats.
|
|
4
9
|
|
|
5
10
|
## Features
|
|
6
11
|
|
|
7
12
|
- DES encryption and decryption
|
|
13
|
+
- **Class-based API** - Create multiple independent instances with different configurations
|
|
8
14
|
- Multiple cipher modes: ECB, CBC, CFB, OFB, CTR
|
|
9
15
|
- Multiple padding schemes: PKCS7, ISO10126, Zero, None
|
|
10
16
|
- Output formats: Base64, Hexadecimal
|
|
17
|
+
- **Custom IV support** - Provide your own Initialization Vector
|
|
11
18
|
- Native implementation for both iOS and Android
|
|
12
19
|
- TurboModule support for improved performance
|
|
20
|
+
- Pre-built options arrays for easy UI integration
|
|
21
|
+
- Full TypeScript support
|
|
22
|
+
|
|
23
|
+
## Compatibility
|
|
24
|
+
|
|
25
|
+
| Platform | Minimum Version |
|
|
26
|
+
| ------------ | --------------- |
|
|
27
|
+
| iOS | 13.0+ |
|
|
28
|
+
| Android | API 21+ (5.0) |
|
|
29
|
+
| React Native | 0.71+ |
|
|
13
30
|
|
|
14
31
|
## Installation
|
|
15
32
|
|
|
@@ -39,30 +56,23 @@ No additional setup required. The library auto-links on Android.
|
|
|
39
56
|
|
|
40
57
|
## Usage
|
|
41
58
|
|
|
42
|
-
### Basic Example
|
|
59
|
+
### Basic Example - Using the DesMachine Class
|
|
43
60
|
|
|
44
61
|
```typescript
|
|
45
|
-
import {
|
|
46
|
-
setMachineParams,
|
|
47
|
-
encrypt,
|
|
48
|
-
decrypt,
|
|
49
|
-
Mode,
|
|
50
|
-
Padding,
|
|
51
|
-
Format,
|
|
52
|
-
} from 'react-native-des-machine';
|
|
62
|
+
import { DesMachine } from 'react-native-des-machine';
|
|
53
63
|
|
|
54
|
-
//
|
|
55
|
-
|
|
64
|
+
// Create a DES machine instance with your encryption key
|
|
65
|
+
const machine = new DesMachine({
|
|
56
66
|
key: 'mySecretKey123', // minimum 8 characters
|
|
57
67
|
});
|
|
58
68
|
|
|
59
69
|
// Encrypt text
|
|
60
|
-
const encrypted = encrypt('Hello World!');
|
|
70
|
+
const encrypted = machine.encrypt('Hello World!');
|
|
61
71
|
console.log('Encrypted:', encrypted);
|
|
62
72
|
// Output: "Encrypted: 2jmj7l5rSw0yVb/vlWAYkK/YBwk="
|
|
63
73
|
|
|
64
74
|
// Decrypt text
|
|
65
|
-
const decrypted = decrypt(encrypted);
|
|
75
|
+
const decrypted = machine.decrypt(encrypted);
|
|
66
76
|
console.log('Decrypted:', decrypted);
|
|
67
77
|
// Output: "Decrypted: Hello World!"
|
|
68
78
|
```
|
|
@@ -70,65 +80,220 @@ console.log('Decrypted:', decrypted);
|
|
|
70
80
|
### Advanced Configuration
|
|
71
81
|
|
|
72
82
|
```typescript
|
|
73
|
-
import {
|
|
74
|
-
setMachineParams,
|
|
75
|
-
encrypt,
|
|
76
|
-
decrypt,
|
|
77
|
-
Mode,
|
|
78
|
-
Padding,
|
|
79
|
-
Format,
|
|
80
|
-
} from 'react-native-des-machine';
|
|
83
|
+
import { DesMachine, Mode, Padding, Format } from 'react-native-des-machine';
|
|
81
84
|
|
|
82
|
-
//
|
|
83
|
-
|
|
85
|
+
// Create a machine with custom mode, padding, and output format
|
|
86
|
+
const machine = new DesMachine({
|
|
84
87
|
key: 'mySecretKey123',
|
|
85
88
|
mode: Mode.CBC, // Cipher Block Chaining mode
|
|
86
89
|
padding: Padding.PKCS7, // PKCS7 padding
|
|
87
90
|
outputFormat: Format.HEX, // Hexadecimal output
|
|
88
91
|
});
|
|
89
92
|
|
|
90
|
-
const encrypted = encrypt('Sensitive data');
|
|
93
|
+
const encrypted = machine.encrypt('Sensitive data');
|
|
91
94
|
console.log('Encrypted (hex):', encrypted);
|
|
92
|
-
// Output: "Encrypted (hex): 4a6f686e446f65..."
|
|
93
95
|
|
|
94
|
-
const decrypted = decrypt(encrypted);
|
|
96
|
+
const decrypted = machine.decrypt(encrypted);
|
|
95
97
|
console.log('Decrypted:', decrypted);
|
|
96
98
|
```
|
|
97
99
|
|
|
100
|
+
### Using Custom Initialization Vector (IV)
|
|
101
|
+
|
|
102
|
+
For non-ECB modes, you can provide a custom IV:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { DesMachine, Mode } from 'react-native-des-machine';
|
|
106
|
+
|
|
107
|
+
const machine = new DesMachine({
|
|
108
|
+
key: 'mySecretKey123',
|
|
109
|
+
iv: 'custom88', // Exactly 8 characters for DES
|
|
110
|
+
mode: Mode.CBC,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const encrypted = machine.encrypt('Secret message');
|
|
114
|
+
const decrypted = machine.decrypt(encrypted);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
> **Note:** If `iv` is not provided for non-ECB modes, the first 8 bytes of the key are used as the IV.
|
|
118
|
+
|
|
119
|
+
### Multiple Instances with Different Configurations
|
|
120
|
+
|
|
121
|
+
One of the key features is the ability to create multiple independent instances:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { DesMachine, Mode, Format } from 'react-native-des-machine';
|
|
125
|
+
|
|
126
|
+
// Machine for API communication (Base64 output)
|
|
127
|
+
const apiMachine = new DesMachine({
|
|
128
|
+
key: 'apiSecretKey',
|
|
129
|
+
mode: Mode.CBC,
|
|
130
|
+
outputFormat: Format.BASE64,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Machine for local storage (Hex output)
|
|
134
|
+
const storageMachine = new DesMachine({
|
|
135
|
+
key: 'storageKey1',
|
|
136
|
+
mode: Mode.ECB,
|
|
137
|
+
outputFormat: Format.HEX,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Use them independently
|
|
141
|
+
const apiData = apiMachine.encrypt('API payload');
|
|
142
|
+
const storageData = storageMachine.encrypt('Local data');
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Quick Functions for One-off Operations
|
|
146
|
+
|
|
147
|
+
For simple one-time encryption/decryption without creating an instance:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { encrypt, decrypt } from 'react-native-des-machine';
|
|
151
|
+
|
|
152
|
+
// Encrypt with params
|
|
153
|
+
const encrypted = encrypt({ key: 'mySecretKey123' }, 'Hello World');
|
|
154
|
+
|
|
155
|
+
// Decrypt with same params
|
|
156
|
+
const decrypted = decrypt({ key: 'mySecretKey123' }, encrypted);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Factory Function
|
|
160
|
+
|
|
161
|
+
Alternative way to create instances:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { createDesMachine } from 'react-native-des-machine';
|
|
165
|
+
|
|
166
|
+
const machine = createDesMachine({ key: 'mySecretKey123' });
|
|
167
|
+
const encrypted = machine.encrypt('Hello');
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Using Pre-built Options for UI
|
|
171
|
+
|
|
172
|
+
The library exports pre-built option arrays for building UI components:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import {
|
|
176
|
+
modeOptions,
|
|
177
|
+
paddingOptions,
|
|
178
|
+
formatOptions,
|
|
179
|
+
} from 'react-native-des-machine';
|
|
180
|
+
|
|
181
|
+
// modeOptions structure:
|
|
182
|
+
// [
|
|
183
|
+
// { label: 'ECB (Electronic Codebook)', value: 'ECB' },
|
|
184
|
+
// { label: 'CBC (Cipher Block Chaining)', value: 'CBC' },
|
|
185
|
+
// { label: 'CFB (Cipher Feedback)', value: 'CFB' },
|
|
186
|
+
// { label: 'OFB (Output Feedback)', value: 'OFB' },
|
|
187
|
+
// { label: 'CTR (Counter)', value: 'CTR' },
|
|
188
|
+
// ]
|
|
189
|
+
|
|
190
|
+
// Use with React Native Picker or any dropdown component
|
|
191
|
+
<Picker selectedValue={selectedMode} onValueChange={setSelectedMode}>
|
|
192
|
+
{modeOptions.map((option) => (
|
|
193
|
+
<Picker.Item key={option.value} label={option.label} value={option.value} />
|
|
194
|
+
))}
|
|
195
|
+
</Picker>;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### React Hook Example
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { useMemo } from 'react';
|
|
202
|
+
import { DesMachine, Mode, Padding, Format } from 'react-native-des-machine';
|
|
203
|
+
import type {
|
|
204
|
+
ModeEncryptionType,
|
|
205
|
+
PaddingEncryptionType,
|
|
206
|
+
OutputFormatType,
|
|
207
|
+
} from 'react-native-des-machine';
|
|
208
|
+
|
|
209
|
+
function useDesMachine(
|
|
210
|
+
key: string,
|
|
211
|
+
mode: ModeEncryptionType = Mode.ECB,
|
|
212
|
+
padding: PaddingEncryptionType = Padding.PKCS7,
|
|
213
|
+
outputFormat: OutputFormatType = Format.BASE64
|
|
214
|
+
) {
|
|
215
|
+
const machine = useMemo(() => {
|
|
216
|
+
if (key.length < 8) return null;
|
|
217
|
+
try {
|
|
218
|
+
return new DesMachine({ key, mode, padding, outputFormat });
|
|
219
|
+
} catch {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}, [key, mode, padding, outputFormat]);
|
|
223
|
+
|
|
224
|
+
return machine;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Usage in component
|
|
228
|
+
function MyComponent() {
|
|
229
|
+
const [key, setKey] = useState('defaultKey');
|
|
230
|
+
const machine = useDesMachine(key);
|
|
231
|
+
|
|
232
|
+
const handleEncrypt = (text: string) => {
|
|
233
|
+
if (!machine) {
|
|
234
|
+
Alert.alert('Error', 'Invalid key');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
return machine.encrypt(text);
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
98
242
|
## API Reference
|
|
99
243
|
|
|
100
|
-
###
|
|
244
|
+
### DesMachine Class
|
|
245
|
+
|
|
246
|
+
The main class for DES encryption and decryption.
|
|
101
247
|
|
|
102
|
-
|
|
248
|
+
#### Constructor
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
new DesMachine(params: DesMachineParams)
|
|
252
|
+
```
|
|
103
253
|
|
|
104
|
-
|
|
254
|
+
Creates a new DES machine instance.
|
|
105
255
|
|
|
106
|
-
|
|
107
|
-
| -------------- | ----------------------- | -------- | ---------- | ------------------------------------- |
|
|
108
|
-
| `key` | `string` | Yes | - | Encryption key (minimum 8 characters) |
|
|
109
|
-
| `mode` | `ModeEncryptionType` | No | `'ECB'` | Cipher mode |
|
|
110
|
-
| `padding` | `PaddingEncryptionType` | No | `'PKCS7'` | Padding scheme |
|
|
111
|
-
| `outputFormat` | `OutputFormatType` | No | `'BASE64'` | Output encoding format |
|
|
256
|
+
**Throws:**
|
|
112
257
|
|
|
113
|
-
|
|
258
|
+
- `Error` if key is missing or less than 8 characters
|
|
259
|
+
- `Error` if iv is provided but not exactly 8 characters
|
|
114
260
|
|
|
115
|
-
|
|
261
|
+
#### Methods
|
|
116
262
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
263
|
+
| Method | Parameters | Returns | Description |
|
|
264
|
+
| ---------------------- | --------------------------- | ------------------ | ---------------------------------- |
|
|
265
|
+
| `encrypt(text)` | `text: string` | `string` | Encrypt plaintext |
|
|
266
|
+
| `decrypt(text)` | `text: string` | `string` | Decrypt ciphertext |
|
|
267
|
+
| `getParams()` | - | `DesMachineParams` | Get current params (key/iv masked) |
|
|
268
|
+
| `updateParams(params)` | `Partial<DesMachineParams>` | `void` | Update mode, padding, or format |
|
|
120
269
|
|
|
121
|
-
###
|
|
270
|
+
### DesMachineParams
|
|
122
271
|
|
|
123
|
-
|
|
272
|
+
| Parameter | Type | Required | Default | Description |
|
|
273
|
+
| -------------- | ----------------------- | -------- | ---------- | --------------------------------------- |
|
|
274
|
+
| `key` | `string` | Yes | - | Encryption key (minimum 8 characters) |
|
|
275
|
+
| `iv` | `string` | No | - | Initialization Vector (exactly 8 chars) |
|
|
276
|
+
| `mode` | `ModeEncryptionType` | No | `'ECB'` | Cipher mode |
|
|
277
|
+
| `padding` | `PaddingEncryptionType` | No | `'PKCS7'` | Padding scheme |
|
|
278
|
+
| `outputFormat` | `OutputFormatType` | No | `'BASE64'` | Output encoding format |
|
|
124
279
|
|
|
125
|
-
|
|
126
|
-
- **Returns:** Decrypted plaintext string
|
|
127
|
-
- **Throws:** Error if `setMachineParams()` has not been called
|
|
280
|
+
### Quick Functions
|
|
128
281
|
|
|
129
|
-
|
|
282
|
+
#### `encrypt(params: DesMachineParams, text: string): string`
|
|
130
283
|
|
|
131
|
-
|
|
284
|
+
Quick encrypt without creating an instance.
|
|
285
|
+
|
|
286
|
+
#### `decrypt(params: DesMachineParams, text: string): string`
|
|
287
|
+
|
|
288
|
+
Quick decrypt without creating an instance.
|
|
289
|
+
|
|
290
|
+
#### `createDesMachine(params: DesMachineParams): DesMachine`
|
|
291
|
+
|
|
292
|
+
Factory function to create a DesMachine instance.
|
|
293
|
+
|
|
294
|
+
### Constants
|
|
295
|
+
|
|
296
|
+
#### Mode
|
|
132
297
|
|
|
133
298
|
| Constant | Value | Description |
|
|
134
299
|
| ---------- | ------- | ----------------------------- |
|
|
@@ -138,7 +303,7 @@ Decrypt ciphertext using the configured DES parameters.
|
|
|
138
303
|
| `Mode.OFB` | `'OFB'` | Output Feedback |
|
|
139
304
|
| `Mode.CTR` | `'CTR'` | Counter |
|
|
140
305
|
|
|
141
|
-
|
|
306
|
+
#### Padding
|
|
142
307
|
|
|
143
308
|
| Constant | Value | Description |
|
|
144
309
|
| ------------------ | ------------ | ------------------------ |
|
|
@@ -147,18 +312,46 @@ Decrypt ciphertext using the configured DES parameters.
|
|
|
147
312
|
| `Padding.ZERO` | `'ZERO'` | Zero padding |
|
|
148
313
|
| `Padding.NONE` | `'NONE'` | No padding |
|
|
149
314
|
|
|
150
|
-
|
|
315
|
+
#### Format
|
|
151
316
|
|
|
152
317
|
| Constant | Value | Description |
|
|
153
318
|
| --------------- | ---------- | ------------------------- |
|
|
154
319
|
| `Format.BASE64` | `'BASE64'` | Base64 encoding (default) |
|
|
155
320
|
| `Format.HEX` | `'HEX'` | Hexadecimal encoding |
|
|
156
321
|
|
|
322
|
+
### Pre-built Options Arrays
|
|
323
|
+
|
|
324
|
+
| Export | Type | Description |
|
|
325
|
+
| ---------------- | -------------------------------------- | --------------------------- |
|
|
326
|
+
| `modeOptions` | `OptionsList<ModeEncryptionType>[]` | Mode options with labels |
|
|
327
|
+
| `paddingOptions` | `OptionsList<PaddingEncryptionType>[]` | Padding options with labels |
|
|
328
|
+
| `formatOptions` | `OptionsList<OutputFormatType>[]` | Format options with labels |
|
|
329
|
+
|
|
330
|
+
Each option has the structure: `{ label: string, value: string }`
|
|
331
|
+
|
|
157
332
|
## TypeScript Support
|
|
158
333
|
|
|
159
334
|
The library includes full TypeScript definitions:
|
|
160
335
|
|
|
161
336
|
```typescript
|
|
337
|
+
import {
|
|
338
|
+
// Main class
|
|
339
|
+
DesMachine,
|
|
340
|
+
createDesMachine,
|
|
341
|
+
// Quick functions
|
|
342
|
+
encrypt,
|
|
343
|
+
decrypt,
|
|
344
|
+
// Constants
|
|
345
|
+
Mode,
|
|
346
|
+
Padding,
|
|
347
|
+
Format,
|
|
348
|
+
// Pre-built options
|
|
349
|
+
modeOptions,
|
|
350
|
+
paddingOptions,
|
|
351
|
+
formatOptions,
|
|
352
|
+
} from 'react-native-des-machine';
|
|
353
|
+
|
|
354
|
+
// Types
|
|
162
355
|
import type {
|
|
163
356
|
DesMachineParams,
|
|
164
357
|
ModeEncryptionType,
|
|
@@ -167,6 +360,25 @@ import type {
|
|
|
167
360
|
} from 'react-native-des-machine';
|
|
168
361
|
```
|
|
169
362
|
|
|
363
|
+
## Complete Exports
|
|
364
|
+
|
|
365
|
+
| Export | Type | Description |
|
|
366
|
+
| ----------------------- | -------- | ------------------------------------ |
|
|
367
|
+
| `DesMachine` | Class | Main class for encryption/decryption |
|
|
368
|
+
| `createDesMachine` | Function | Factory to create DesMachine |
|
|
369
|
+
| `encrypt` | Function | Quick encrypt with params |
|
|
370
|
+
| `decrypt` | Function | Quick decrypt with params |
|
|
371
|
+
| `Mode` | Constant | Cipher mode constants |
|
|
372
|
+
| `Padding` | Constant | Padding scheme constants |
|
|
373
|
+
| `Format` | Constant | Output format constants |
|
|
374
|
+
| `modeOptions` | Array | Pre-built mode options for UI |
|
|
375
|
+
| `paddingOptions` | Array | Pre-built padding options for UI |
|
|
376
|
+
| `formatOptions` | Array | Pre-built format options for UI |
|
|
377
|
+
| `DesMachineParams` | Type | TypeScript type for params |
|
|
378
|
+
| `ModeEncryptionType` | Type | TypeScript type for modes |
|
|
379
|
+
| `PaddingEncryptionType` | Type | TypeScript type for padding |
|
|
380
|
+
| `OutputFormatType` | Type | TypeScript type for formats |
|
|
381
|
+
|
|
170
382
|
## Security Notice
|
|
171
383
|
|
|
172
384
|
DES is considered cryptographically weak by modern standards due to its 56-bit key size. For production applications requiring strong encryption, consider using AES or other modern algorithms. This library is suitable for:
|
|
@@ -175,12 +387,23 @@ DES is considered cryptographically weak by modern standards due to its 56-bit k
|
|
|
175
387
|
- Educational purposes
|
|
176
388
|
- Low-security applications
|
|
177
389
|
|
|
390
|
+
## Author
|
|
391
|
+
|
|
392
|
+
- GitHub: [@NeRo8](https://github.com/NeRo8)
|
|
393
|
+
|
|
178
394
|
## Contributing
|
|
179
395
|
|
|
180
396
|
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
181
397
|
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
182
398
|
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
183
399
|
|
|
400
|
+
## Support
|
|
401
|
+
|
|
402
|
+
If you find this library helpful, please consider giving it a star on GitHub!
|
|
403
|
+
|
|
404
|
+
- [Report a bug](https://github.com/NeRo8/react-native-des-machine/issues)
|
|
405
|
+
- [Request a feature](https://github.com/NeRo8/react-native-des-machine/issues)
|
|
406
|
+
|
|
184
407
|
## License
|
|
185
408
|
|
|
186
409
|
MIT
|
|
@@ -4,7 +4,6 @@ import android.util.Base64
|
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
5
|
import com.facebook.react.bridge.ReadableMap
|
|
6
6
|
import javax.crypto.Cipher
|
|
7
|
-
import javax.crypto.SecretKey
|
|
8
7
|
import javax.crypto.SecretKeyFactory
|
|
9
8
|
import javax.crypto.spec.DESKeySpec
|
|
10
9
|
import javax.crypto.spec.IvParameterSpec
|
|
@@ -12,97 +11,100 @@ import javax.crypto.spec.IvParameterSpec
|
|
|
12
11
|
class DesMachineModule(reactContext: ReactApplicationContext) :
|
|
13
12
|
NativeDesMachineSpec(reactContext) {
|
|
14
13
|
|
|
15
|
-
private var secretKey: SecretKey? = null
|
|
16
|
-
private var mode: String = MODE_ECB
|
|
17
|
-
private var padding: String = PADDING_PKCS7
|
|
18
|
-
private var outputFormat: String = FORMAT_BASE64
|
|
19
|
-
private var ivSpec: IvParameterSpec? = null
|
|
20
|
-
|
|
21
14
|
/**
|
|
22
|
-
*
|
|
15
|
+
* Encrypt the provided plaintext using DES algorithm.
|
|
16
|
+
* Stateless operation - all parameters are passed with each call.
|
|
17
|
+
*
|
|
23
18
|
* @param params ReadableMap containing:
|
|
24
19
|
* - key: String (required, minimum 8 characters)
|
|
25
20
|
* - mode: String (optional, default: ECB) - ECB, CBC, CFB, OFB, CTR
|
|
26
21
|
* - padding: String (optional, default: PKCS7) - PKCS7, ISO10126, ZERO, NONE
|
|
27
22
|
* - outputFormat: String (optional, default: BASE64) - BASE64, HEX
|
|
23
|
+
* @param text The plaintext to encrypt
|
|
24
|
+
* @return Encrypted string in the configured output format (BASE64 or HEX)
|
|
28
25
|
*/
|
|
29
|
-
override fun
|
|
30
|
-
|
|
31
|
-
val
|
|
32
|
-
?: throw IllegalArgumentException("Key is required")
|
|
33
|
-
require(key.length >= 8) { "DES key must be at least 8 characters long" }
|
|
34
|
-
|
|
35
|
-
// Extract optional parameters with defaults
|
|
36
|
-
mode = params.getString("mode") ?: MODE_ECB
|
|
37
|
-
padding = params.getString("padding") ?: PADDING_PKCS7
|
|
38
|
-
outputFormat = params.getString("outputFormat") ?: FORMAT_BASE64
|
|
26
|
+
override fun encrypt(params: ReadableMap, text: String): String {
|
|
27
|
+
val config = parseParams(params)
|
|
28
|
+
val cipher = createCipher(Cipher.ENCRYPT_MODE, config)
|
|
39
29
|
|
|
40
|
-
|
|
41
|
-
val
|
|
42
|
-
val desKeySpec = DESKeySpec(keyBytes)
|
|
43
|
-
val keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM)
|
|
44
|
-
secretKey = keyFactory.generateSecret(desKeySpec)
|
|
30
|
+
val inputBytes = applyPaddingIfNeeded(text.toByteArray(Charsets.UTF_8), config.padding)
|
|
31
|
+
val encryptedBytes = cipher.doFinal(inputBytes)
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
if (mode != MODE_ECB) {
|
|
48
|
-
// Use first 8 bytes of key as IV (DES block size is 8 bytes)
|
|
49
|
-
val ivBytes = keyBytes.copyOf(8)
|
|
50
|
-
ivSpec = IvParameterSpec(ivBytes)
|
|
51
|
-
}
|
|
33
|
+
return formatOutput(encryptedBytes, config.outputFormat)
|
|
52
34
|
}
|
|
53
35
|
|
|
54
36
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
37
|
+
* Decrypt the provided ciphertext using DES algorithm.
|
|
38
|
+
* Stateless operation - all parameters are passed with each call.
|
|
39
|
+
*
|
|
40
|
+
* @param params ReadableMap containing:
|
|
41
|
+
* - key: String (required, minimum 8 characters)
|
|
42
|
+
* - mode: String (optional, default: ECB) - ECB, CBC, CFB, OFB, CTR
|
|
43
|
+
* - padding: String (optional, default: PKCS7) - PKCS7, ISO10126, ZERO, NONE
|
|
44
|
+
* - outputFormat: String (optional, default: BASE64) - BASE64, HEX
|
|
45
|
+
* @param text Encrypted string in the configured format (BASE64 or HEX)
|
|
46
|
+
* @return Decrypted plaintext
|
|
58
47
|
*/
|
|
59
|
-
override fun
|
|
60
|
-
val
|
|
61
|
-
|
|
48
|
+
override fun decrypt(params: ReadableMap, text: String): String {
|
|
49
|
+
val config = parseParams(params)
|
|
50
|
+
val cipher = createCipher(Cipher.DECRYPT_MODE, config)
|
|
62
51
|
|
|
63
|
-
val
|
|
64
|
-
val
|
|
52
|
+
val encryptedBytes = parseInput(text, config.outputFormat)
|
|
53
|
+
val decryptedBytes = cipher.doFinal(encryptedBytes)
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} else {
|
|
69
|
-
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec)
|
|
70
|
-
}
|
|
55
|
+
return String(removePaddingIfNeeded(decryptedBytes, config.padding), Charsets.UTF_8)
|
|
56
|
+
}
|
|
71
57
|
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Parse and validate parameters from ReadableMap.
|
|
60
|
+
*/
|
|
61
|
+
private fun parseParams(params: ReadableMap): DesConfig {
|
|
62
|
+
val key = params.getString("key")
|
|
63
|
+
?: throw IllegalArgumentException("Key is required")
|
|
64
|
+
require(key.length >= 8) { "DES key must be at least 8 characters long" }
|
|
74
65
|
|
|
75
|
-
|
|
66
|
+
val iv = params.getString("iv")
|
|
67
|
+
if (iv != null) {
|
|
68
|
+
require(iv.length == 8) { "IV must be exactly 8 characters long" }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return DesConfig(
|
|
72
|
+
key = key,
|
|
73
|
+
iv = iv,
|
|
74
|
+
mode = params.getString("mode") ?: MODE_ECB,
|
|
75
|
+
padding = params.getString("padding") ?: PADDING_PKCS7,
|
|
76
|
+
outputFormat = params.getString("outputFormat") ?: FORMAT_BASE64
|
|
77
|
+
)
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
/**
|
|
79
|
-
*
|
|
80
|
-
* @param text Encrypted string in the configured format (BASE64 or HEX)
|
|
81
|
-
* @return Decrypted plaintext
|
|
81
|
+
* Create and initialize a cipher with the given configuration.
|
|
82
82
|
*/
|
|
83
|
-
|
|
84
|
-
val
|
|
85
|
-
|
|
83
|
+
private fun createCipher(opMode: Int, config: DesConfig): Cipher {
|
|
84
|
+
val keyBytes = config.key.toByteArray(Charsets.UTF_8)
|
|
85
|
+
val desKeySpec = DESKeySpec(keyBytes)
|
|
86
|
+
val keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM)
|
|
87
|
+
val secretKey = keyFactory.generateSecret(desKeySpec)
|
|
86
88
|
|
|
87
|
-
val transformation = buildTransformation()
|
|
89
|
+
val transformation = buildTransformation(config.mode, config.padding)
|
|
88
90
|
val cipher = Cipher.getInstance(transformation)
|
|
89
91
|
|
|
90
|
-
if (mode == MODE_ECB) {
|
|
91
|
-
cipher.init(
|
|
92
|
+
if (config.mode == MODE_ECB) {
|
|
93
|
+
cipher.init(opMode, secretKey)
|
|
92
94
|
} else {
|
|
93
|
-
|
|
95
|
+
// Use provided IV or first 8 bytes of key as IV (DES block size is 8 bytes)
|
|
96
|
+
val ivBytes = config.iv?.toByteArray(Charsets.UTF_8) ?: keyBytes.copyOf(8)
|
|
97
|
+
val ivSpec = IvParameterSpec(ivBytes)
|
|
98
|
+
cipher.init(opMode, secretKey, ivSpec)
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
val decryptedBytes = cipher.doFinal(encryptedBytes)
|
|
98
|
-
|
|
99
|
-
return String(removePaddingIfNeeded(decryptedBytes), Charsets.UTF_8)
|
|
101
|
+
return cipher
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
/**
|
|
103
105
|
* Build the cipher transformation string based on mode and padding.
|
|
104
106
|
*/
|
|
105
|
-
private fun buildTransformation(): String {
|
|
107
|
+
private fun buildTransformation(mode: String, padding: String): String {
|
|
106
108
|
val javaPadding = when (padding) {
|
|
107
109
|
PADDING_PKCS7 -> "PKCS5Padding" // PKCS5 is equivalent to PKCS7 for DES
|
|
108
110
|
PADDING_ISO10126 -> "ISO10126Padding"
|
|
@@ -115,7 +117,7 @@ class DesMachineModule(reactContext: ReactApplicationContext) :
|
|
|
115
117
|
/**
|
|
116
118
|
* Apply manual padding for ZERO padding mode.
|
|
117
119
|
*/
|
|
118
|
-
private fun applyPaddingIfNeeded(data: ByteArray): ByteArray {
|
|
120
|
+
private fun applyPaddingIfNeeded(data: ByteArray, padding: String): ByteArray {
|
|
119
121
|
if (padding != PADDING_ZERO && padding != PADDING_NONE) {
|
|
120
122
|
return data
|
|
121
123
|
}
|
|
@@ -135,7 +137,7 @@ class DesMachineModule(reactContext: ReactApplicationContext) :
|
|
|
135
137
|
/**
|
|
136
138
|
* Remove manual padding for ZERO padding mode.
|
|
137
139
|
*/
|
|
138
|
-
private fun removePaddingIfNeeded(data: ByteArray): ByteArray {
|
|
140
|
+
private fun removePaddingIfNeeded(data: ByteArray, padding: String): ByteArray {
|
|
139
141
|
if (padding != PADDING_ZERO) {
|
|
140
142
|
return data
|
|
141
143
|
}
|
|
@@ -151,7 +153,7 @@ class DesMachineModule(reactContext: ReactApplicationContext) :
|
|
|
151
153
|
/**
|
|
152
154
|
* Format encrypted bytes to the configured output format.
|
|
153
155
|
*/
|
|
154
|
-
private fun formatOutput(bytes: ByteArray): String {
|
|
156
|
+
private fun formatOutput(bytes: ByteArray, outputFormat: String): String {
|
|
155
157
|
return when (outputFormat) {
|
|
156
158
|
FORMAT_HEX -> bytes.joinToString("") { "%02x".format(it) }
|
|
157
159
|
else -> Base64.encodeToString(bytes, Base64.NO_WRAP)
|
|
@@ -161,13 +163,24 @@ class DesMachineModule(reactContext: ReactApplicationContext) :
|
|
|
161
163
|
/**
|
|
162
164
|
* Parse input string from the configured format to bytes.
|
|
163
165
|
*/
|
|
164
|
-
private fun parseInput(text: String): ByteArray {
|
|
166
|
+
private fun parseInput(text: String, outputFormat: String): ByteArray {
|
|
165
167
|
return when (outputFormat) {
|
|
166
168
|
FORMAT_HEX -> text.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
|
|
167
169
|
else -> Base64.decode(text, Base64.NO_WRAP)
|
|
168
170
|
}
|
|
169
171
|
}
|
|
170
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Data class to hold DES configuration.
|
|
175
|
+
*/
|
|
176
|
+
private data class DesConfig(
|
|
177
|
+
val key: String,
|
|
178
|
+
val iv: String?,
|
|
179
|
+
val mode: String,
|
|
180
|
+
val padding: String,
|
|
181
|
+
val outputFormat: String
|
|
182
|
+
)
|
|
183
|
+
|
|
171
184
|
companion object {
|
|
172
185
|
const val NAME = NativeDesMachineSpec.NAME
|
|
173
186
|
|
|
@@ -175,10 +188,6 @@ class DesMachineModule(reactContext: ReactApplicationContext) :
|
|
|
175
188
|
|
|
176
189
|
// Mode constants
|
|
177
190
|
private const val MODE_ECB = "ECB"
|
|
178
|
-
private const val MODE_CBC = "CBC"
|
|
179
|
-
private const val MODE_CFB = "CFB"
|
|
180
|
-
private const val MODE_OFB = "OFB"
|
|
181
|
-
private const val MODE_CTR = "CTR"
|
|
182
191
|
|
|
183
192
|
// Padding constants
|
|
184
193
|
private const val PADDING_PKCS7 = "PKCS7"
|
package/ios/DesMachine.h
CHANGED
|
@@ -3,10 +3,4 @@
|
|
|
3
3
|
|
|
4
4
|
@interface DesMachine : NSObject <NativeDesMachineSpec>
|
|
5
5
|
|
|
6
|
-
@property (nonatomic, strong) NSData *secretKey;
|
|
7
|
-
@property (nonatomic, strong) NSData *ivData;
|
|
8
|
-
@property (nonatomic, copy) NSString *mode;
|
|
9
|
-
@property (nonatomic, copy) NSString *padding;
|
|
10
|
-
@property (nonatomic, copy) NSString *outputFormat;
|
|
11
|
-
|
|
12
6
|
@end
|