crypto_key.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. const unusable = (name, prop = 'algorithm.name') => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
  2. const isAlgorithm = (algorithm, name) => algorithm.name === name;
  3. function getHashLength(hash) {
  4. return parseInt(hash.name.slice(4), 10);
  5. }
  6. function checkHashLength(algorithm, expected) {
  7. const actual = getHashLength(algorithm.hash);
  8. if (actual !== expected)
  9. throw unusable(`SHA-${expected}`, 'algorithm.hash');
  10. }
  11. function getNamedCurve(alg) {
  12. switch (alg) {
  13. case 'ES256':
  14. return 'P-256';
  15. case 'ES384':
  16. return 'P-384';
  17. case 'ES512':
  18. return 'P-521';
  19. default:
  20. throw new Error('unreachable');
  21. }
  22. }
  23. function checkUsage(key, usage) {
  24. if (usage && !key.usages.includes(usage)) {
  25. throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
  26. }
  27. }
  28. export function checkSigCryptoKey(key, alg, usage) {
  29. switch (alg) {
  30. case 'HS256':
  31. case 'HS384':
  32. case 'HS512': {
  33. if (!isAlgorithm(key.algorithm, 'HMAC'))
  34. throw unusable('HMAC');
  35. checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
  36. break;
  37. }
  38. case 'RS256':
  39. case 'RS384':
  40. case 'RS512': {
  41. if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))
  42. throw unusable('RSASSA-PKCS1-v1_5');
  43. checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
  44. break;
  45. }
  46. case 'PS256':
  47. case 'PS384':
  48. case 'PS512': {
  49. if (!isAlgorithm(key.algorithm, 'RSA-PSS'))
  50. throw unusable('RSA-PSS');
  51. checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
  52. break;
  53. }
  54. case 'Ed25519':
  55. case 'EdDSA': {
  56. if (!isAlgorithm(key.algorithm, 'Ed25519'))
  57. throw unusable('Ed25519');
  58. break;
  59. }
  60. case 'ML-DSA-44':
  61. case 'ML-DSA-65':
  62. case 'ML-DSA-87': {
  63. if (!isAlgorithm(key.algorithm, alg))
  64. throw unusable(alg);
  65. break;
  66. }
  67. case 'ES256':
  68. case 'ES384':
  69. case 'ES512': {
  70. if (!isAlgorithm(key.algorithm, 'ECDSA'))
  71. throw unusable('ECDSA');
  72. const expected = getNamedCurve(alg);
  73. const actual = key.algorithm.namedCurve;
  74. if (actual !== expected)
  75. throw unusable(expected, 'algorithm.namedCurve');
  76. break;
  77. }
  78. default:
  79. throw new TypeError('CryptoKey does not support this operation');
  80. }
  81. checkUsage(key, usage);
  82. }
  83. export function checkEncCryptoKey(key, alg, usage) {
  84. switch (alg) {
  85. case 'A128GCM':
  86. case 'A192GCM':
  87. case 'A256GCM': {
  88. if (!isAlgorithm(key.algorithm, 'AES-GCM'))
  89. throw unusable('AES-GCM');
  90. const expected = parseInt(alg.slice(1, 4), 10);
  91. const actual = key.algorithm.length;
  92. if (actual !== expected)
  93. throw unusable(expected, 'algorithm.length');
  94. break;
  95. }
  96. case 'A128KW':
  97. case 'A192KW':
  98. case 'A256KW': {
  99. if (!isAlgorithm(key.algorithm, 'AES-KW'))
  100. throw unusable('AES-KW');
  101. const expected = parseInt(alg.slice(1, 4), 10);
  102. const actual = key.algorithm.length;
  103. if (actual !== expected)
  104. throw unusable(expected, 'algorithm.length');
  105. break;
  106. }
  107. case 'ECDH': {
  108. switch (key.algorithm.name) {
  109. case 'ECDH':
  110. case 'X25519':
  111. break;
  112. default:
  113. throw unusable('ECDH or X25519');
  114. }
  115. break;
  116. }
  117. case 'PBES2-HS256+A128KW':
  118. case 'PBES2-HS384+A192KW':
  119. case 'PBES2-HS512+A256KW':
  120. if (!isAlgorithm(key.algorithm, 'PBKDF2'))
  121. throw unusable('PBKDF2');
  122. break;
  123. case 'RSA-OAEP':
  124. case 'RSA-OAEP-256':
  125. case 'RSA-OAEP-384':
  126. case 'RSA-OAEP-512': {
  127. if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))
  128. throw unusable('RSA-OAEP');
  129. checkHashLength(key.algorithm, parseInt(alg.slice(9), 10) || 1);
  130. break;
  131. }
  132. default:
  133. throw new TypeError('CryptoKey does not support this operation');
  134. }
  135. checkUsage(key, usage);
  136. }