react-native-des-machine 0.1.1 → 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 +192 -57
- 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 +1 -8
- package/src/NativeDesMachine.ts +26 -3
- package/src/index.ts +164 -13
package/README.md
CHANGED
|
@@ -10,9 +10,11 @@ A React Native TurboModule that provides DES (Data Encryption Standard) encrypti
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
12
|
- DES encryption and decryption
|
|
13
|
+
- **Class-based API** - Create multiple independent instances with different configurations
|
|
13
14
|
- Multiple cipher modes: ECB, CBC, CFB, OFB, CTR
|
|
14
15
|
- Multiple padding schemes: PKCS7, ISO10126, Zero, None
|
|
15
16
|
- Output formats: Base64, Hexadecimal
|
|
17
|
+
- **Custom IV support** - Provide your own Initialization Vector
|
|
16
18
|
- Native implementation for both iOS and Android
|
|
17
19
|
- TurboModule support for improved performance
|
|
18
20
|
- Pre-built options arrays for easy UI integration
|
|
@@ -54,23 +56,23 @@ No additional setup required. The library auto-links on Android.
|
|
|
54
56
|
|
|
55
57
|
## Usage
|
|
56
58
|
|
|
57
|
-
### Basic Example
|
|
59
|
+
### Basic Example - Using the DesMachine Class
|
|
58
60
|
|
|
59
61
|
```typescript
|
|
60
|
-
import {
|
|
62
|
+
import { DesMachine } from 'react-native-des-machine';
|
|
61
63
|
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
+
// Create a DES machine instance with your encryption key
|
|
65
|
+
const machine = new DesMachine({
|
|
64
66
|
key: 'mySecretKey123', // minimum 8 characters
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
// Encrypt text
|
|
68
|
-
const encrypted = encrypt('Hello World!');
|
|
70
|
+
const encrypted = machine.encrypt('Hello World!');
|
|
69
71
|
console.log('Encrypted:', encrypted);
|
|
70
72
|
// Output: "Encrypted: 2jmj7l5rSw0yVb/vlWAYkK/YBwk="
|
|
71
73
|
|
|
72
74
|
// Decrypt text
|
|
73
|
-
const decrypted = decrypt(encrypted);
|
|
75
|
+
const decrypted = machine.decrypt(encrypted);
|
|
74
76
|
console.log('Decrypted:', decrypted);
|
|
75
77
|
// Output: "Decrypted: Hello World!"
|
|
76
78
|
```
|
|
@@ -78,34 +80,96 @@ console.log('Decrypted:', decrypted);
|
|
|
78
80
|
### Advanced Configuration
|
|
79
81
|
|
|
80
82
|
```typescript
|
|
81
|
-
import {
|
|
82
|
-
setMachineParams,
|
|
83
|
-
encrypt,
|
|
84
|
-
decrypt,
|
|
85
|
-
Mode,
|
|
86
|
-
Padding,
|
|
87
|
-
Format,
|
|
88
|
-
} from 'react-native-des-machine';
|
|
83
|
+
import { DesMachine, Mode, Padding, Format } from 'react-native-des-machine';
|
|
89
84
|
|
|
90
|
-
//
|
|
91
|
-
|
|
85
|
+
// Create a machine with custom mode, padding, and output format
|
|
86
|
+
const machine = new DesMachine({
|
|
92
87
|
key: 'mySecretKey123',
|
|
93
88
|
mode: Mode.CBC, // Cipher Block Chaining mode
|
|
94
89
|
padding: Padding.PKCS7, // PKCS7 padding
|
|
95
90
|
outputFormat: Format.HEX, // Hexadecimal output
|
|
96
91
|
});
|
|
97
92
|
|
|
98
|
-
const encrypted = encrypt('Sensitive data');
|
|
93
|
+
const encrypted = machine.encrypt('Sensitive data');
|
|
99
94
|
console.log('Encrypted (hex):', encrypted);
|
|
100
|
-
// Output: "Encrypted (hex): 4a6f686e446f65..."
|
|
101
95
|
|
|
102
|
-
const decrypted = decrypt(encrypted);
|
|
96
|
+
const decrypted = machine.decrypt(encrypted);
|
|
103
97
|
console.log('Decrypted:', decrypted);
|
|
104
98
|
```
|
|
105
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
|
+
|
|
106
170
|
### Using Pre-built Options for UI
|
|
107
171
|
|
|
108
|
-
The library exports pre-built option arrays
|
|
172
|
+
The library exports pre-built option arrays for building UI components:
|
|
109
173
|
|
|
110
174
|
```typescript
|
|
111
175
|
import {
|
|
@@ -131,36 +195,101 @@ import {
|
|
|
131
195
|
</Picker>;
|
|
132
196
|
```
|
|
133
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
|
+
|
|
134
242
|
## API Reference
|
|
135
243
|
|
|
136
|
-
###
|
|
244
|
+
### DesMachine Class
|
|
245
|
+
|
|
246
|
+
The main class for DES encryption and decryption.
|
|
247
|
+
|
|
248
|
+
#### Constructor
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
new DesMachine(params: DesMachineParams)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Creates a new DES machine instance.
|
|
137
255
|
|
|
138
|
-
|
|
256
|
+
**Throws:**
|
|
139
257
|
|
|
140
|
-
|
|
258
|
+
- `Error` if key is missing or less than 8 characters
|
|
259
|
+
- `Error` if iv is provided but not exactly 8 characters
|
|
141
260
|
|
|
142
|
-
|
|
143
|
-
| -------------- | ----------------------- | -------- | ---------- | ------------------------------------- |
|
|
144
|
-
| `key` | `string` | Yes | - | Encryption key (minimum 8 characters) |
|
|
145
|
-
| `mode` | `ModeEncryptionType` | No | `'ECB'` | Cipher mode |
|
|
146
|
-
| `padding` | `PaddingEncryptionType` | No | `'PKCS7'` | Padding scheme |
|
|
147
|
-
| `outputFormat` | `OutputFormatType` | No | `'BASE64'` | Output encoding format |
|
|
261
|
+
#### Methods
|
|
148
262
|
|
|
149
|
-
|
|
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 |
|
|
150
269
|
|
|
151
|
-
|
|
270
|
+
### DesMachineParams
|
|
152
271
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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 |
|
|
156
279
|
|
|
157
|
-
|
|
280
|
+
### Quick Functions
|
|
158
281
|
|
|
159
|
-
|
|
282
|
+
#### `encrypt(params: DesMachineParams, text: string): string`
|
|
160
283
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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.
|
|
164
293
|
|
|
165
294
|
### Constants
|
|
166
295
|
|
|
@@ -192,8 +321,6 @@ Decrypt ciphertext using the configured DES parameters.
|
|
|
192
321
|
|
|
193
322
|
### Pre-built Options Arrays
|
|
194
323
|
|
|
195
|
-
These arrays are useful for building UI components like dropdowns or pickers:
|
|
196
|
-
|
|
197
324
|
| Export | Type | Description |
|
|
198
325
|
| ---------------- | -------------------------------------- | --------------------------- |
|
|
199
326
|
| `modeOptions` | `OptionsList<ModeEncryptionType>[]` | Mode options with labels |
|
|
@@ -208,8 +335,10 @@ The library includes full TypeScript definitions:
|
|
|
208
335
|
|
|
209
336
|
```typescript
|
|
210
337
|
import {
|
|
211
|
-
//
|
|
212
|
-
|
|
338
|
+
// Main class
|
|
339
|
+
DesMachine,
|
|
340
|
+
createDesMachine,
|
|
341
|
+
// Quick functions
|
|
213
342
|
encrypt,
|
|
214
343
|
decrypt,
|
|
215
344
|
// Constants
|
|
@@ -233,20 +362,22 @@ import type {
|
|
|
233
362
|
|
|
234
363
|
## Complete Exports
|
|
235
364
|
|
|
236
|
-
| Export | Type | Description
|
|
237
|
-
| ----------------------- | -------- |
|
|
238
|
-
| `
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
243
|
-
| `
|
|
244
|
-
| `
|
|
245
|
-
| `
|
|
246
|
-
| `
|
|
247
|
-
| `
|
|
248
|
-
| `
|
|
249
|
-
| `
|
|
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 |
|
|
250
381
|
|
|
251
382
|
## Security Notice
|
|
252
383
|
|
|
@@ -256,6 +387,10 @@ DES is considered cryptographically weak by modern standards due to its 56-bit k
|
|
|
256
387
|
- Educational purposes
|
|
257
388
|
- Low-security applications
|
|
258
389
|
|
|
390
|
+
## Author
|
|
391
|
+
|
|
392
|
+
- GitHub: [@NeRo8](https://github.com/NeRo8)
|
|
393
|
+
|
|
259
394
|
## Contributing
|
|
260
395
|
|
|
261
396
|
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
@@ -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
|