@breakside/jskit 2024.34.0 → 2024.40.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.
Files changed (86) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/JS/JSClass.js +4 -1
  7. package/Frameworks/Foundation.jsframework/JS/JSNodeURLSessionStreamTask.js +1 -1
  8. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  9. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  10. package/Frameworks/SecurityKit.jsframework/JS/SECCOSE.js +135 -0
  11. package/Frameworks/SecurityKit.jsframework/JS/SECCipher+HTML.js +231 -70
  12. package/Frameworks/SecurityKit.jsframework/JS/SECCipher+Node.js +155 -60
  13. package/Frameworks/SecurityKit.jsframework/JS/SECCipher.js +125 -54
  14. package/Frameworks/SecurityKit.jsframework/JS/SECDataKey.js +5 -4
  15. package/Frameworks/SecurityKit.jsframework/JS/SECHMAC+HTML.js +15 -11
  16. package/Frameworks/SecurityKit.jsframework/JS/SECHMAC+Node.js +17 -3
  17. package/Frameworks/SecurityKit.jsframework/JS/SECHTMLDeviceAuthentication.js +139 -106
  18. package/Frameworks/SecurityKit.jsframework/JS/SECHTMLKey.js +17 -0
  19. package/Frameworks/SecurityKit.jsframework/JS/SECHash.js +1 -0
  20. package/Frameworks/SecurityKit.jsframework/JS/SECJSONWebAlgorithms.js +9 -1
  21. package/Frameworks/SecurityKit.jsframework/JS/SECJSONWebEncryption.js +391 -0
  22. package/Frameworks/SecurityKit.jsframework/JS/SECJSONWebToken.js +1 -1
  23. package/Frameworks/SecurityKit.jsframework/JS/SECKey.js +14 -1
  24. package/Frameworks/SecurityKit.jsframework/JS/SECNodeKey.js +66 -1
  25. package/Frameworks/SecurityKit.jsframework/JS/SECSign+HTML.js +2 -27
  26. package/Frameworks/SecurityKit.jsframework/JS/SECSign+Node.js +103 -278
  27. package/Frameworks/SecurityKit.jsframework/JS/SECSign.js +27 -0
  28. package/Frameworks/SecurityKit.jsframework/JS/SECVerify+Node.js +60 -57
  29. package/Frameworks/SecurityKit.jsframework/JS/SecurityKit.js +1 -0
  30. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  31. package/Frameworks/SecurityKit.jsframework/sources.json +6 -0
  32. package/Info.json +2 -2
  33. package/Node/KeyCommand.js +8 -1
  34. package/Node/io.breakside.jskit-bundle.js +2 -2
  35. package/Node/jskit +1 -0
  36. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  37. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  38. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  39. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  40. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  41. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  42. package/Root/Frameworks/DBKit/DBEncryptedObject.js +2 -2
  43. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  44. package/Root/Frameworks/DOM/Info.yaml +1 -1
  45. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  46. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  47. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  48. package/Root/Frameworks/Foundation/JSClass.js +4 -1
  49. package/Root/Frameworks/Foundation/JSNodeURLSessionStreamTask.js +1 -1
  50. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  51. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  52. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  53. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  54. package/Root/Frameworks/NotificationKit/NKWebPushService.js +2 -2
  55. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  56. package/Root/Frameworks/PDFKit/PDFEncryption.js +1 -1
  57. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  58. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  59. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  60. package/Root/Frameworks/SecurityKit/SECCOSE.js +135 -0
  61. package/Root/Frameworks/SecurityKit/SECCipher+HTML.js +231 -70
  62. package/Root/Frameworks/SecurityKit/SECCipher+Node.js +155 -60
  63. package/Root/Frameworks/SecurityKit/SECCipher.js +125 -54
  64. package/Root/Frameworks/SecurityKit/SECDataKey.js +5 -4
  65. package/Root/Frameworks/SecurityKit/SECHMAC+HTML.js +15 -11
  66. package/Root/Frameworks/SecurityKit/SECHMAC+Node.js +17 -3
  67. package/Root/Frameworks/SecurityKit/SECHTMLDeviceAuthentication.js +139 -106
  68. package/Root/Frameworks/SecurityKit/SECHTMLKey.js +17 -0
  69. package/Root/Frameworks/SecurityKit/SECHash.js +1 -0
  70. package/Root/Frameworks/SecurityKit/SECJSONWebAlgorithms.js +9 -1
  71. package/Root/Frameworks/SecurityKit/SECJSONWebEncryption.js +391 -0
  72. package/Root/Frameworks/SecurityKit/SECJSONWebToken.js +1 -1
  73. package/Root/Frameworks/SecurityKit/SECKey.js +14 -1
  74. package/Root/Frameworks/SecurityKit/SECNodeKey.js +66 -1
  75. package/Root/Frameworks/SecurityKit/SECSign+HTML.js +2 -27
  76. package/Root/Frameworks/SecurityKit/SECSign+Node.js +103 -278
  77. package/Root/Frameworks/SecurityKit/SECSign.js +27 -0
  78. package/Root/Frameworks/SecurityKit/SECVerify+Node.js +60 -57
  79. package/Root/Frameworks/SecurityKit/SecurityKit.js +1 -0
  80. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  81. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  82. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  83. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  84. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  85. package/package.json +1 -1
  86. package/Root/Templates/workspace/.gitignore +0 -4
@@ -16,6 +16,8 @@
16
16
  // #import Foundation
17
17
  // #import "SECCipher.js"
18
18
  // #import "SECNodeKey.js"
19
+ // #import "SECASN1Parser.js"
20
+ // #import "SECJSONWebAlgorithms.js"
19
21
  // jshint node: true
20
22
  'use strict';
21
23
 
@@ -27,7 +29,9 @@ SECCipher.definePropertiesFromExtensions({
27
29
  if (!completion){
28
30
  completion = Promise.completion(Promise.resolveNonNull);
29
31
  }
30
- this.encrypt(key.keyData, wrappingKey, completion, target);
32
+ key.getData(function(keyData){
33
+ this.encrypt(keyData, wrappingKey, completion, target);
34
+ }, this);
31
35
  return completion.promise;
32
36
  },
33
37
 
@@ -45,15 +49,21 @@ SECCipher.definePropertiesFromExtensions({
45
49
  return completion.promise;
46
50
  },
47
51
 
52
+ });
53
+
54
+ SECCipherAES.definePropertiesFromExtensions({
55
+
48
56
  createKey: function(completion, target){
49
57
  if (!completion){
50
58
  completion = Promise.completion(Promise.resolveNonNull);
51
59
  }
52
- crypto.randomBytes(this.keyByteLength, function(error, keyBytes){
60
+ crypto.generateKey("aes", {length: this.keyBitLength}, function(error, nodeKeyObject){
53
61
  if (error){
54
62
  completion.call(target, null);
55
63
  }else{
56
- completion.call(target, SECNodeKey.initWithData(JSData.initWithNodeBuffer(keyBytes)));
64
+ var key = SECNodeKey.initWithNodeKeyObject(nodeKeyObject);
65
+ key.id = JSSHA1Hash(UUID.init().bytes).base64URLStringRepresentation();
66
+ completion.call(target, key);
57
67
  }
58
68
  });
59
69
  return completion.promise;
@@ -71,8 +81,8 @@ SECCipher.definePropertiesFromExtensions({
71
81
 
72
82
  SECCipherAESCipherBlockChaining.definePropertiesFromExtensions({
73
83
 
74
- _cipherNameForKey: function(key){
75
- switch (key.keyData.length){
84
+ nodeCipherName: JSLazyInitProperty(function(){
85
+ switch (this.keyByteLength){
76
86
  case 16:
77
87
  return 'AES-128-CBC';
78
88
  case 24:
@@ -81,26 +91,20 @@ SECCipherAESCipherBlockChaining.definePropertiesFromExtensions({
81
91
  return 'AES-256-CBC';
82
92
  }
83
93
  return null;
84
- },
94
+ }),
85
95
 
86
96
  encrypt: function(data, key, completion, target){
87
97
  if (!completion){
88
98
  completion = Promise.completion(Promise.resolveNonNull);
89
99
  }
90
- var name = this._cipherNameForKey(key);
91
- crypto.randomBytes(16, function(error, iv){
92
- if (error){
93
- completion.call(target, null);
94
- return;
95
- }
96
- if (name === null){
97
- completion.call(target, null);
98
- return;
99
- }
100
- var cipher = crypto.createCipheriv(name, key.keyData, iv);
101
- var chunks = [iv, cipher.update(data), cipher.final()];
102
- completion.call(target, JSData.initWithChunks(chunks));
103
- });
100
+ if (this.nodeCipherName === null){
101
+ JSRunLoop.main.schedule(completion, target, null);
102
+ return completion.promise;
103
+ }
104
+ var iv = this.iv !== null ? this.iv : this.randomIV();
105
+ var cipher = crypto.createCipheriv(this.nodeCipherName, key.nodeKeyObject, iv);
106
+ var chunks = [iv, cipher.update(data), cipher.final()];
107
+ JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
104
108
  return completion.promise;
105
109
  },
106
110
 
@@ -109,14 +113,14 @@ SECCipherAESCipherBlockChaining.definePropertiesFromExtensions({
109
113
  completion = Promise.completion(Promise.resolveNonNull);
110
114
  }
111
115
  try{
112
- var name = this._cipherNameForKey(key);
113
- if (name === null){
116
+ if (this.nodeCipherName === null){
114
117
  JSRunLoop.main.schedule(completion, target, null);
115
118
  return completion.promise;
116
119
  }
117
- var iv = data.subdataInRange(JSRange(0, 16));
118
- var cipher = crypto.createDecipheriv(name, key.keyData, iv);
119
- var chunks = [cipher.update(data.subdataInRange(JSRange(16, data.length - 16))), cipher.final()];
120
+ var iv = data.subdataInRange(JSRange(0, this.ivByteLength));
121
+ var ciphertext = data.subdataInRange(JSRange(this.ivByteLength, data.length - this.ivByteLength));
122
+ var cipher = crypto.createDecipheriv(this.nodeCipherName, key.nodeKeyObject, iv);
123
+ var chunks = [cipher.update(ciphertext), cipher.final()];
120
124
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
121
125
  }catch (e){
122
126
  JSRunLoop.main.schedule(completion, target, null);
@@ -128,8 +132,8 @@ SECCipherAESCipherBlockChaining.definePropertiesFromExtensions({
128
132
 
129
133
  SECCipherAESCounter.definePropertiesFromExtensions({
130
134
 
131
- _cipherNameForKey: function(key){
132
- switch (key.keyData.length){
135
+ nodeCipherName: JSLazyInitProperty(function(){
136
+ switch (this.keyByteLength){
133
137
  case 16:
134
138
  return 'AES-128-CTR';
135
139
  case 24:
@@ -138,7 +142,7 @@ SECCipherAESCounter.definePropertiesFromExtensions({
138
142
  return 'AES-256-CTR';
139
143
  }
140
144
  return null;
141
- },
145
+ }),
142
146
 
143
147
  encrypt: function(data, key, completion, target){
144
148
  if (!completion){
@@ -148,8 +152,7 @@ SECCipherAESCounter.definePropertiesFromExtensions({
148
152
  JSRunLoop.main.schedule(completion, target, null);
149
153
  return completion.promise;
150
154
  }
151
- var name = this._cipherNameForKey(key);
152
- if (name === null){
155
+ if (this.nodeCipherName === null){
153
156
  JSRunLoop.main.schedule(completion, target, null);
154
157
  return completion.promise;
155
158
  }
@@ -165,7 +168,7 @@ SECCipherAESCounter.definePropertiesFromExtensions({
165
168
  ]);
166
169
  var iv = JSData.initWithLength(16);
167
170
  nonce.copyTo(iv, 0);
168
- var cipher = crypto.createCipheriv(name, key.keyData, iv);
171
+ var cipher = crypto.createCipheriv(this.nodeCipherName, key.nodeKeyObject, iv);
169
172
  var chunks = [nonce, cipher.update(data), cipher.final()];
170
173
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
171
174
  return completion.promise;
@@ -176,15 +179,14 @@ SECCipherAESCounter.definePropertiesFromExtensions({
176
179
  completion = Promise.completion(Promise.resolveNonNull);
177
180
  }
178
181
  try{
179
- var name = this._cipherNameForKey(key);
180
- if (name === null){
182
+ if (this.nodeCipherName === null){
181
183
  JSRunLoop.main.schedule(completion, target, null);
182
184
  return completion.promise;
183
185
  }
184
186
  var nonce = data.subdataInRange(JSRange(0, 8));
185
187
  var iv = JSData.initWithLength(16);
186
188
  nonce.copyTo(iv, 0);
187
- var cipher = crypto.createDecipheriv(name, key.keyData, iv);
189
+ var cipher = crypto.createDecipheriv(this.nodeCipherName, key.nodeKeyObject, iv);
188
190
  var chunks = [cipher.update(data.subdataInRange(JSRange(8, data.length - 8))), cipher.final()];
189
191
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
190
192
  }catch (e){
@@ -197,8 +199,8 @@ SECCipherAESCounter.definePropertiesFromExtensions({
197
199
 
198
200
  SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
199
201
 
200
- _cipherNameForKey: function(key){
201
- switch (key.keyData.length){
202
+ nodeCipherName: JSLazyInitProperty(function(){
203
+ switch (this.keyByteLength){
202
204
  case 16:
203
205
  return 'id-aes128-GCM';
204
206
  case 24:
@@ -207,53 +209,47 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
207
209
  return 'id-aes256-GCM';
208
210
  }
209
211
  return null;
210
- },
212
+ }),
211
213
 
212
- encryptWithNonce: function(nonce, data, key, completion, target, _ivLength){
214
+ encrypt: function(data, key, completion, target){
213
215
  if (!completion){
214
216
  completion = Promise.completion(Promise.resolveNonNull);
215
217
  }
216
- var name = this._cipherNameForKey(key);
217
- if (name === null){
218
+ if (this.nodeCipherName === null){
218
219
  JSRunLoop.main.schedule(completion, target, null);
219
220
  return completion.promise;
220
221
  }
221
- if (_ivLength === undefined){
222
- _ivLength = nonce.length;
222
+ var iv = this.iv !== null ? this.iv : this.randomIV();
223
+ var cipher = crypto.createCipheriv(this.nodeCipherName, key.nodeKeyObject, iv);
224
+ if (this.additionalData){
225
+ cipher.setAAD(this.additionalData);
223
226
  }
224
- var iv = JSData.initWithLength(_ivLength);
225
- nonce.copyTo(iv, 0);
226
- var cipher = crypto.createCipheriv(name, key.keyData, iv);
227
- var chunks = [nonce, cipher.update(data), cipher.final()];
228
- var tagLength = 16;
229
- var tag = JSData.initWithLength(tagLength);
227
+ var chunks = [iv, cipher.update(data), cipher.final()];
228
+ var tag = JSData.initWithLength(this.tagByteLength);
230
229
  cipher.getAuthTag().copyTo(tag, 0);
231
230
  chunks.push(tag);
232
231
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
233
232
  return completion.promise;
234
233
  },
235
234
 
236
- decryptWithNonceLength: function(nonceLength, data, key, completion, target, _ivLength){
235
+ decrypt: function(data, key, completion, target){
237
236
  if (!completion){
238
237
  completion = Promise.completion(Promise.resolveNonNull);
239
238
  }
240
239
  try{
241
- var name = this._cipherNameForKey(key);
242
- if (name === null){
240
+ if (this.nodeCipherName === null){
243
241
  JSRunLoop.main.schedule(completion, target, null);
244
242
  return completion.promise;
245
243
  }
246
- var nonce = data.subdataInRange(JSRange(0, nonceLength));
247
- if (_ivLength === undefined){
248
- _ivLength = nonceLength;
244
+ var iv = data.subdataInRange(JSRange(0, this.ivByteLength));
245
+ var ciphertext = data.subdataInRange(JSRange(this.ivByteLength, data.length - this.ivByteLength - this.tagByteLength));
246
+ var tag = data.subdataInRange(JSRange(data.length - this.tagByteLength, this.tagByteLength));
247
+ var cipher = crypto.createDecipheriv(this.nodeCipherName, key.nodeKeyObject, iv);
248
+ if (this.additionalData){
249
+ cipher.setAAD(this.additionalData);
249
250
  }
250
- var iv = JSData.initWithLength(_ivLength);
251
- nonce.copyTo(iv, 0);
252
- var cipher = crypto.createDecipheriv(name, key.keyData, iv);
253
- var tagLength = 16;
254
- var tag = data.subdataInRange(JSRange(data.length - tagLength, tagLength));
255
251
  cipher.setAuthTag(tag);
256
- var chunks = [cipher.update(data.subdataInRange(JSRange(nonceLength, data.length - nonceLength - tagLength))), cipher.final()];
252
+ var chunks = [cipher.update(ciphertext), cipher.final()];
257
253
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
258
254
  }catch(e){
259
255
  JSRunLoop.main.schedule(completion, target, null);
@@ -263,6 +259,105 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
263
259
 
264
260
  });
265
261
 
262
+ SECCipherRSAOAEP.definePropertiesFromExtensions({
263
+
264
+ encrypt: function(data, key, completion, target){
265
+ if (!completion){
266
+ completion = Promise.completion(Promise.resolveNonNull);
267
+ }
268
+ var options = {
269
+ key: key.nodeKeyObject,
270
+ oaepHash: this.hash
271
+ };
272
+ if (this.label !== null){
273
+ options.oaepLabel = this.label;
274
+ }
275
+ var encryptedBuffer = crypto.publicEncrypt(options, data);
276
+ JSRunLoop.main.schedule(completion, target, JSData.initWithNodeBuffer(encryptedBuffer));
277
+ return completion.promise;
278
+ },
279
+
280
+ decrypt: function(data, key, completion, target){
281
+ if (!completion){
282
+ completion = Promise.completion(Promise.resolveNonNull);
283
+ }
284
+ var options = {
285
+ key: key.nodeKeyObject,
286
+ oaepHash: this.hash
287
+ };
288
+ if (this.label !== null){
289
+ options.oaepLabel = this.label;
290
+ }
291
+ var decryptedBuffer = crypto.privateDecrypt(options, data);
292
+ JSRunLoop.main.schedule(completion, target, JSData.initWithNodeBuffer(decryptedBuffer));
293
+ return completion.promise;
294
+ },
295
+
296
+ createKey: function(completion, target){
297
+ if (!completion){
298
+ completion = Promise.completion(Promise.resolveNonNull);
299
+ }
300
+ var options = {
301
+ modulusLength: this.modulusLength,
302
+ publicExponent: this.publicExponent
303
+ };
304
+ crypto.generateKeyPair("rsa", options, function(err, publicNodeKey, privateNodeKey){
305
+ if (err){
306
+ completion.call(target, null);
307
+ return;
308
+ }
309
+ var privateKey = SECNodeKey.initWithNodeKeyObject(privateNodeKey, {alg: SECJSONWebAlgorithms.Algorithm.rsaOAEP});
310
+ privateKey.publicKey = SECNodeKey.initWithNodeKeyObject(publicNodeKey, {alg: SECJSONWebAlgorithms.Algorithm.rsaOAEP});
311
+ privateKey.id = privateKey.publicKey.id = JSSHA1Hash(UUID.init().bytes).base64URLStringRepresentation();
312
+ completion.call(target, privateKey);
313
+ });
314
+ return completion.promise;
315
+ },
316
+
317
+ createKeyWithData: function(data, completion, target){
318
+ if (!completion){
319
+ completion = Promise.completion(Promise.resolveNonNull);
320
+ }
321
+ var parser;
322
+ var key;
323
+ try{
324
+ parser = SECASN1Parser.initWithPEM(data, "RSA PRIVATE KEY");
325
+ key = crypto.createPrivateKey({key: parser.der, format: "der"});
326
+ }catch (e){
327
+ try {
328
+ parser = SECASN1Parser.initWithPEM(data, "RSA PUBLIC KEY");
329
+ key = crypto.createPublicKey({key: parser.der, format: "der"});
330
+ }catch (e){
331
+ parser = SECASN1Parser.initWithDER(data);
332
+ var sequence = parser.parse();
333
+ if (sequence.length > 2){
334
+ key = crypto.createPrivateKey({key: parser.der, format: "der"});
335
+ }else{
336
+ key = crypto.createPublicKey({key: parser.der, format: "der"});
337
+ }
338
+ }
339
+ }
340
+ JSRunLoop.main.schedule(completion, target, SECNodeKey.initWithNodeKeyObject(key));
341
+ return completion.promise;
342
+ },
343
+
344
+ createKeyFromJWK: function(jwk, completion, target){
345
+ if (!completion){
346
+ completion = Promise.completion(Promise.resolveNonNull);
347
+ }
348
+ var key = null;
349
+ if (jwk.d){
350
+ key = crypto.createPrivateKey({key: jwk, format: "jwk"});
351
+ }else{
352
+ key = crypto.createPublicKey({key: jwk, format: "jwk"});
353
+ }
354
+ key.id = jwk.kid || null;
355
+ JSRunLoop.main.schedule(completion, target, SECNodeKey.initWithNodeKeyObject(key));
356
+ return completion.promise;
357
+ },
358
+
359
+ });
360
+
266
361
  SECCipher.getRandomData = function(length){
267
362
  return JSData.initWithNodeBuffer(crypto.randomBytes(length));
268
363
  };
@@ -21,31 +21,34 @@
21
21
 
22
22
  JSClass("SECCipher", JSObject, {
23
23
 
24
- initWithAlgorithm: function(algorithm, keyBitLength){
25
- if (keyBitLength === undefined){
26
- keyBitLength = 256;
24
+ algorithm: null,
25
+
26
+ initWithAlgorithm: function(algorithm, options){
27
+ if (options === undefined){
28
+ options = {};
29
+ }else if (typeof(options) === "number"){
30
+ options = {
31
+ keyBitLength: options
32
+ };
27
33
  }
28
- if (keyBitLength % 8 !== 0){
34
+ if (options.keyBitLength !== undefined && (options.keyBitLength % 8 !== 0)){
29
35
  throw new Error("Invalid keyBitLength, must be a multiple of 8");
30
36
  }
31
37
  switch (algorithm){
32
38
  case SECCipher.Algorithm.aesCipherBlockChaining:
33
- return SECCipherAESCipherBlockChaining.initWithKeyBitLength(keyBitLength);
39
+ return SECCipherAESCipherBlockChaining.initWithOptions(options);
34
40
  case SECCipher.Algorithm.aesCounter:
35
- return SECCipherAESCounter.initWithKeyBitLength(keyBitLength);
41
+ return SECCipherAESCounter.initWithOptions(options);
36
42
  case SECCipher.Algorithm.aesGaloisCounterMode:
37
- return SECCipherAESGaloisCounterMode.initWithKeyBitLength(keyBitLength);
43
+ return SECCipherAESGaloisCounterMode.initWithOptions(options);
38
44
  case SECCipher.Algorithm.rivestCipher4:
39
- return SECCipherRC4.initWithKeyBitLength(keyBitLength);
45
+ return SECCipherRC4.init();
46
+ case SECCipher.Algorithm.rsaOAEP:
47
+ return SECCipherRSAOAEP.initWithOptions(options);
40
48
  }
41
49
  return null;
42
50
  },
43
51
 
44
- initWithKeyBitLength: function(keyBitLength){
45
- this.keyBitLength = keyBitLength;
46
- this.keyByteLength = keyBitLength >> 3;
47
- },
48
-
49
52
  encrypt: function(data, key, completion, target){
50
53
  // Implemented in subclasses
51
54
  if (!completion){
@@ -122,6 +125,53 @@ JSClass("SECCipher", JSObject, {
122
125
  return completion.promise;
123
126
  },
124
127
 
128
+ createKeyFromJWK: function(jwk, completion, target){
129
+ // Implemented in subclasses
130
+ if (!completion){
131
+ completion = Promise.completion(Promise.resolveNonNull);
132
+ }
133
+ JSRunLoop.main.schedule(completion, target, null);
134
+ return completion.promise;
135
+ },
136
+
137
+ createKeyFromKeystore: function(keystore, kid, completion, target){
138
+ // Implemented in subclasses
139
+ if (!completion){
140
+ completion = Promise.completion(Promise.resolveNonNull);
141
+ }
142
+ JSRunLoop.main.schedule(completion, target, null);
143
+ return completion.promise;
144
+ },
145
+
146
+ createKeyWithPassphrase: function(passphrase, salt, iterations, hash, completion, target){
147
+ // Implemented in subclasses
148
+ if (!completion){
149
+ completion = Promise.completion(Promise.resolveNonNull);
150
+ }
151
+ JSRunLoop.main.schedule(completion, target, null);
152
+ return completion.promise;
153
+ },
154
+
155
+ });
156
+
157
+ SECCipher.Algorithm = {
158
+ aesCipherBlockChaining: 'aes_cbc',
159
+ aesCounter: 'aes_ctr',
160
+ aesGaloisCounterMode: 'aes_gcm',
161
+ rivestCipher4: 'rc4',
162
+ rsaOAEP: "rsa_oaep"
163
+ };
164
+
165
+ JSClass("SECCipherAES", SECCipher, {
166
+
167
+ keyBitLength: null,
168
+ keyByteLength: null,
169
+
170
+ initWithOptions: function(options){
171
+ this.keyBitLength = options.keyBitLength || 256;
172
+ this.keyByteLength = this.keyBitLength >> 3;
173
+ },
174
+
125
175
  createKeyFromJWK: function(jwk, completion, target){
126
176
  if (!completion){
127
177
  completion = Promise.completion(Promise.resolveNonNull);
@@ -184,11 +234,29 @@ JSClass("SECCipher", JSObject, {
184
234
 
185
235
  });
186
236
 
187
- JSClass("SECCipherAESCipherBlockChaining", SECCipher, {
237
+ JSClass("SECCipherAESCipherBlockChaining", SECCipherAES, {
238
+
239
+ algorithm: SECCipher.Algorithm.aesCipherBlockChaining,
240
+ ivByteLength: 16,
241
+ iv: null,
242
+
243
+ initWithOptions: function(options){
244
+ SECCipherAESCipherBlockChaining.$super.initWithOptions.call(this, options);
245
+ if (options.iv){
246
+ this.iv = options.iv;
247
+ this.ivByteLength = this.iv.length;
248
+ }
249
+ },
250
+
251
+ randomIV: function(){
252
+ return SECCipher.getRandomData(this.ivByteLength);
253
+ },
254
+
188
255
  });
189
256
 
190
- JSClass("SECCipherAESCounter", SECCipher, {
257
+ JSClass("SECCipherAESCounter", SECCipherAES, {
191
258
 
259
+ algorithm: SECCipher.Algorithm.aesCounter,
192
260
  encryptedMessageId: 0,
193
261
 
194
262
  ensureUniqueMessageID: function(){
@@ -201,49 +269,57 @@ JSClass("SECCipherAESCounter", SECCipher, {
201
269
 
202
270
  });
203
271
 
204
- JSClass("SECCipherAESGaloisCounterMode", SECCipher, {
272
+ JSClass("SECCipherAESGaloisCounterMode", SECCipherAES, {
205
273
 
206
- encryptedMessageId: 0,
274
+ algorithm: SECCipher.Algorithm.aesGaloisCounterMode,
275
+ iv: null,
276
+ ivByteLength: 16,
277
+ tagByteLength: 16,
278
+ additionalData: null,
207
279
 
208
- ensureUniqueMessageID: function(){
209
- if (this.encryptedMessageId == 9007199254740991){
210
- return false;
280
+ initWithOptions: function(options){
281
+ SECCipherAESGaloisCounterMode.$super.initWithOptions.call(this, options);
282
+ if (options.tagByteLength){
283
+ this.tagByteLength = options.tagByteLength;
211
284
  }
212
- ++this.encryptedMessageId;
213
- return true;
285
+ if (options.additionalData){
286
+ this.additionalData = options.additionalData;
287
+ }
288
+ if (options.iv){
289
+ this.iv = options.iv;
290
+ this.ivByteLength = this.iv.length;
291
+ }else if (options.ivByteLength){
292
+ this.ivByteLength = options.ivByteLength;
293
+ }
294
+ },
295
+
296
+ randomIV: function(){
297
+ return SECCipher.getRandomData(this.ivByteLength);
214
298
  },
215
299
 
216
300
  encrypt: function(data, key, completion, target){
217
- if (!completion){
218
- completion = Promise.completion(Promise.resolveNonNull);
219
- }
220
- if (!this.ensureUniqueMessageID()){
221
- JSRunLoop.main.schedule(completion, target, null);
222
- return completion.promise;
223
- }
224
- var nonce = JSData.initWithArray([
225
- 1,
226
- ((this.encryptedMessageId / 0x100000000) >> 16) & 0xFF,
227
- ((this.encryptedMessageId / 0x100000000) >> 8) & 0xFF,
228
- (this.encryptedMessageId / 0x100000000) & 0xFF,
229
- (this.encryptedMessageId >> 24) & 0xFF,
230
- (this.encryptedMessageId >> 16) & 0xFF,
231
- (this.encryptedMessageId >> 8) & 0xFF,
232
- this.encryptedMessageId & 0xF
233
- ]);
234
- this.encryptWithNonce(nonce, data, key, completion, target, 16);
235
- return completion.promise;
236
301
  },
237
302
 
238
303
  decrypt: function(data, key, completion, target){
239
- return this.decryptWithNonceLength(8, data, key, completion, target, 16);
240
304
  },
241
305
 
242
- encryptWithNonce: function(nonce, data, key, completion, target){
243
- },
306
+ });
244
307
 
245
- decryptWithNonceLength: function(nonceLength, data, key, completion, target){
246
- },
308
+ JSClass("SECCipherRSAOAEP", SECCipher, {
309
+
310
+ hash: null,
311
+ label: null,
312
+ modulusLength: null,
313
+ publicExponent: null,
314
+
315
+ initWithOptions: function(options){
316
+ if (options.label){
317
+ this.label = options.label;
318
+ }
319
+ this.hash = options.hash || SECHash.Algorithm.sha1;
320
+ this.modulusLength = options.modulusLength || 2048;
321
+ this.publicExponent = options.publicExponent || 0x10001;
322
+ }
247
323
 
248
324
  });
249
325
 
@@ -252,6 +328,8 @@ JSClass("SECCipherAESGaloisCounterMode", SECCipher, {
252
328
  // to read the PDFs that already use it.
253
329
  JSClass("SECCipherRC4", SECCipher, {
254
330
 
331
+ algorithm: SECCipher.Algorithm.rivestCipher4,
332
+
255
333
  encrypt: function(data, key, completion, target){
256
334
  if (!completion){
257
335
  completion = Promise.completion(Promise.resolveNonNull);
@@ -265,7 +343,7 @@ JSClass("SECCipherRC4", SECCipher, {
265
343
  var j = 0;
266
344
  var tmp;
267
345
  for (i = 0; i < 256; ++i){
268
- j = (j + S[i] + key.keyData[i % key.keyData.length]) & 0xFF;
346
+ j = (j + S[i] + key.data[i % key.data.length]) & 0xFF;
269
347
  tmp = S[i];
270
348
  S[i] = S[j];
271
349
  S[j] = tmp;
@@ -302,13 +380,6 @@ JSClass("SECCipherRC4", SECCipher, {
302
380
 
303
381
  });
304
382
 
305
- SECCipher.Algorithm = {
306
- aesCipherBlockChaining: 'aes_cbc',
307
- aesCounter: 'aes_ctr',
308
- aesGaloisCounterMode: 'aes_gcm',
309
- rivestCipher4: 'rc4'
310
- };
311
-
312
383
  SECCipher.getRandomData = function(length){
313
384
  // Implemented in environment extensions
314
385
  };
@@ -18,22 +18,23 @@
18
18
 
19
19
  JSClass("SECDataKey", SECKey, {
20
20
 
21
- keyData: null,
21
+ data: null,
22
+ type: SECKey.KeyType.secret,
22
23
 
23
24
  initWithData: function(data){
24
- this.keyData = JSData.initWithCopyOfData(data);
25
+ this.data = JSData.initWithCopyOfData(data);
25
26
  },
26
27
 
27
28
  getData: function(completion, target){
28
29
  if (!completion){
29
30
  completion = Promise.completion(Promise.resolveNonNull);
30
31
  }
31
- JSRunLoop.main.schedule(completion, target, this.keyData);
32
+ JSRunLoop.main.schedule(completion, target, this.data);
32
33
  return completion.promise;
33
34
  },
34
35
 
35
36
  destroy: function(){
36
- this.keyData.zero();
37
+ this.data.zero();
37
38
  }
38
39
 
39
40
  });