te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - SubtleCrypto importKey from PEM - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - SubtleCrypto importKey from PEM - Stack Overflow

programmeradmin4浏览0评论

I am trying to use the SubtleCrypto Web API in Ionic to encrypt data using a public key. I am importing the key in PEM format and then passing it onto window.crypto.subtle.importKey and then using that result into window.crypto.subtle.encrypt

It would appear that there is a problem with the window.crypto.subtle.importKey - I am getting a Uncaught (in promise): DataError when I am trying to import the key.

I am currently using the following methods to import the key:

//Get the public key in CryptoKey format
let importedPublicKey = await window.crypto.subtle.importKey(
    "pkcs8",
    this.pemPublicToArrayBuffer(serverPublicKey),
    {
        name: "RSA-OAEP",
        hash: {name: "SHA-256"}
    },
    true,
    []
);

private pemPublicToArrayBuffer(pem) {
  var b64Lines = this.removeLines(pem);
  var b64Prefix = b64Lines.replace('-----BEGIN PUBLIC KEY-----', '');
  var b64Final = b64Prefix.replace('-----END PUBLIC KEY-----', '');

  return this.base64ToArrayBuffer(b64Final);
}

private base64ToArrayBuffer(b64) {
  var byteString = window.atob(b64);
  var byteArray = new Uint8Array(byteString.length);
  for (var i = 0; i < byteString.length; i++) {
    byteArray[i] = byteString.charCodeAt(i);
  }

  return byteArray;
}

Does anyone possibly know why the key import is failing with the PEM public key?

I am trying to use the SubtleCrypto Web API in Ionic to encrypt data using a public key. I am importing the key in PEM format and then passing it onto window.crypto.subtle.importKey and then using that result into window.crypto.subtle.encrypt

It would appear that there is a problem with the window.crypto.subtle.importKey - I am getting a Uncaught (in promise): DataError when I am trying to import the key.

I am currently using the following methods to import the key:

//Get the public key in CryptoKey format
let importedPublicKey = await window.crypto.subtle.importKey(
    "pkcs8",
    this.pemPublicToArrayBuffer(serverPublicKey),
    {
        name: "RSA-OAEP",
        hash: {name: "SHA-256"}
    },
    true,
    []
);

private pemPublicToArrayBuffer(pem) {
  var b64Lines = this.removeLines(pem);
  var b64Prefix = b64Lines.replace('-----BEGIN PUBLIC KEY-----', '');
  var b64Final = b64Prefix.replace('-----END PUBLIC KEY-----', '');

  return this.base64ToArrayBuffer(b64Final);
}

private base64ToArrayBuffer(b64) {
  var byteString = window.atob(b64);
  var byteArray = new Uint8Array(byteString.length);
  for (var i = 0; i < byteString.length; i++) {
    byteArray[i] = byteString.charCodeAt(i);
  }

  return byteArray;
}

Does anyone possibly know why the key import is failing with the PEM public key?

Share Improve this question asked Feb 18, 2019 at 7:48 TachyonTachyon 2,4113 gold badges24 silver badges49 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 13

I've spent quite some time struggling with this error myself, and now I'm sure I can give you (and anyone else) some good advice on this.

  1. You are passing "pkcs8" as a format to the importKey method, but if you are importing a PUBLIC key, the format is likely to be the "spki" (SubjectPublicKeyInfo) a special format for public keys, while "pkcs8" supposed to be used for PRIVATE keys. That brings us to the next point:

  2. Where did you get this key from? If you are exporting public key with the OpenSSL cli (openssl rsa -pubout -in priv.pem -out pub.pem) then you are getting the key in "spki" format (default one).

  3. You should pass ["encrypt"] as a "usages" parameter to the importKey (instead of an empty array) if you are importing a PUBLIC key, otherwise you will end up with one of the following errors: "SyntaxError: Cannot create a key using the specified key usages" (wrong usage specified for the key) or "InvalidAccessError: key.usages does not permit this operation" (empty array of usages). Things to keep in mind here is that Public keys can be used only to ["encrypt"] and Private keys to ["decrypt"]. I haven't tried to import key pairs though, but as I understand it, you should pass "pkcs8" as a format, and ["encrypt", "decrypt"] for usages.

  4. Even if you set up all the above properly, you may still get the nasty "Uncaught (in promise): DataError", for me it was due to the format mismatch, I've been passing a key in PKCS#1 RSAPublicKey format with the "spki" parameter. So you should probably start from inspecting your key to get exact format and algorithm details from it.

Hope this helps someone. Ivan

I have a public key in pem format encoded in base64, Here is how i used it to load as a public key.

export async function importPublicKey(key) {
  // Decode the base64-encoded PEM string
  let pem = atob(key);

  // Define the PEM header and footer for a public key
  const pemHeader = "-----BEGIN PUBLIC KEY-----";
  const pemFooter = "-----END PUBLIC KEY-----";

  // Extract the base64-encoded content from the PEM string,
  // removing the header and footer. The '-1' in the substring function
  // accounts for the newline character at the end of the header.
  const pemContents = pem.substring(
    pemHeader.length,
    pem.length - pemFooter.length - 1
  );

  // Decode the extracted base64-encoded content to get the binary data
  const binaryStr = window.atob(pemContents);

  // Convert the binary string to an ArrayBuffer
  const buff = str2ab(binaryStr);

  // Function to convert a binary string to an ArrayBuffer
  function str2ab(str) {
    const buffer = new Uint8Array(str.length);
    for (let i = 0; i < str.length; i++) {
      buffer[i] = str.charCodeAt(i);
    }
    return buffer;
  }

  // Import the public key using the Web Crypto API
  return window.crypto.subtle.importKey(
    "spki",             // The format of the key to be imported (SubjectPublicKeyInfo)
    buff,               // The public key data
    {
      name: "RSA-OAEP", // The algorithm the imported key will be used with
      hash: "SHA-256",  // The hash function to be used with the algorithm
    },
    true,               // Whether the key is extractable
    ["encrypt"]         // The intended use for the key (encryption in this case)
  );
}

and to encrypt data using the public key:

export async function encryptWithPublicKey(data, publicKey) {
  const encodedData = new TextEncoder().encode(data);
  const encryptedData = await window.crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
    },
    publicKey,
    encodedData
  );
  return window.btoa(String.fromCharCode(...new Uint8Array(encryptedData)));
}
发布评论

评论列表(0)

  1. 暂无评论