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 CHANGED
@@ -1,15 +1,32 @@
1
1
  # react-native-des-machine
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/react-native-des-machine.svg)](https://www.npmjs.com/package/react-native-des-machine)
4
+ [![npm downloads](https://img.shields.io/npm/dm/react-native-des-machine.svg)](https://www.npmjs.com/package/react-native-des-machine)
5
+ [![license](https://img.shields.io/npm/l/react-native-des-machine.svg)](https://github.com/NeRo8/react-native-des-machine/blob/main/LICENSE)
6
+ [![platform](https://img.shields.io/badge/platform-iOS%20%7C%20Android-lightgrey.svg)](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
- // Initialize the DES machine with your encryption key
55
- setMachineParams({
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
- // Configure with custom mode, padding, and output format
83
- setMachineParams({
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
- ### `setMachineParams(params: DesMachineParams): void`
244
+ ### DesMachine Class
245
+
246
+ The main class for DES encryption and decryption.
101
247
 
102
- Initialize the DES machine with encryption parameters.
248
+ #### Constructor
249
+
250
+ ```typescript
251
+ new DesMachine(params: DesMachineParams)
252
+ ```
103
253
 
104
- #### Parameters
254
+ Creates a new DES machine instance.
105
255
 
106
- | Parameter | Type | Required | Default | Description |
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
- ### `encrypt(text: string): string`
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
- Encrypt plaintext using the configured DES parameters.
261
+ #### Methods
116
262
 
117
- - **Parameters:** `text` - The plaintext string to encrypt
118
- - **Returns:** Encrypted string in the configured output format
119
- - **Throws:** Error if `setMachineParams()` has not been called
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
- ### `decrypt(text: string): string`
270
+ ### DesMachineParams
122
271
 
123
- Decrypt ciphertext using the configured DES parameters.
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
- - **Parameters:** `text` - The encrypted string to decrypt
126
- - **Returns:** Decrypted plaintext string
127
- - **Throws:** Error if `setMachineParams()` has not been called
280
+ ### Quick Functions
128
281
 
129
- ## Constants
282
+ #### `encrypt(params: DesMachineParams, text: string): string`
130
283
 
131
- ### Mode
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
- ### Padding
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
- ### Format
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
- * Set the DES machine parameters including key, mode, padding, and output format.
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 setMachineParams(params: ReadableMap) {
30
- // Extract and validate key
31
- val key = params.getString("key")
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
- // Initialize secret key
41
- val keyBytes = key.toByteArray(Charsets.UTF_8)
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
- // Initialize IV for modes that require it (CBC, CFB, OFB, CTR)
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
- * Encrypt the provided plaintext using DES algorithm.
56
- * @param text The plaintext to encrypt
57
- * @return Encrypted string in the configured output format (BASE64 or HEX)
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 encrypt(text: String): String {
60
- val key = secretKey
61
- ?: throw IllegalStateException("DES not initialized. Call setMachineParams() first.")
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 transformation = buildTransformation()
64
- val cipher = Cipher.getInstance(transformation)
52
+ val encryptedBytes = parseInput(text, config.outputFormat)
53
+ val decryptedBytes = cipher.doFinal(encryptedBytes)
65
54
 
66
- if (mode == MODE_ECB) {
67
- cipher.init(Cipher.ENCRYPT_MODE, key)
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
- val inputBytes = applyPaddingIfNeeded(text.toByteArray(Charsets.UTF_8))
73
- val encryptedBytes = cipher.doFinal(inputBytes)
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
- return formatOutput(encryptedBytes)
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
- * Decrypt the provided ciphertext using DES algorithm.
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
- override fun decrypt(text: String): String {
84
- val key = secretKey
85
- ?: throw IllegalStateException("DES not initialized. Call setMachineParams() first.")
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(Cipher.DECRYPT_MODE, key)
92
+ if (config.mode == MODE_ECB) {
93
+ cipher.init(opMode, secretKey)
92
94
  } else {
93
- cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)
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
- val encryptedBytes = parseInput(text)
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