You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C语言结合OpenSSL生成JWT.io与Google认可的JWT?

C语言原生OpenSSL生成Google合规JWT的问题排查

我要开发一款X应用,必须通过C语言结合原生OpenSSL生成可用于登录Google服务的JWT,其他方案无法满足需求。目前已经用PHP的openssl_sign函数成功实现该功能,但基于OpenSSL 1.0.2编写的C代码始终无法生成JWT.io与Google认可的JWT。

以下是我的C代码:

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getsha(char* msg, char* hash) {
  // This function wont work, yet it returns a 256 byte value as hash.
  // I'm given a key. let's assume its this (but more extravagant).
  char* pky =
      "-----BEGIN PRIVATE KEY-----\nAAAAAAAAAAA==\n-----END PRIVATE KEY-----\n";
  unsigned int psz = strlen(pky), msz = strlen(msg), len = 0;
  memset(hash, 0, 384);  // wipe out output hash
  OpenSSL_add_all_digests();
  BIO* IO = BIO_new_mem_buf(pky, psz);  // make a buffer?
  struct evp_pkey_st* SK = PEM_read_bio_PrivateKey(IO, NULL, NULL, NULL);
  // error out if function fails
  if (!SK) {
    // we reach here if we use the example private key above, but if you replace
    // it with a real private key, this test will pass.
    BIO_free_all(IO);
    EVP_PKEY_free(SK);
    printf("Error getting key\n");
    exit(-1);
  }
  EVP_MD_CTX* X = EVP_MD_CTX_create();
  // We want SHA256 key
  if (!EVP_SignInit(X, EVP_sha256())) {
    printf("Error getting digest\n");
    exit(-1);
  }
  // We want to add our generated JWT
  if (!EVP_SignUpdate(X, msg, msz)) {
    printf("Error updating key/digest\n");
    exit(-1);
  }
  // Then we sign the key
  // This function gives warnings if the string isn't an unsigned char
  // but does that matter if I'm only feeding in base64 values?
  EVP_SignFinal(X, (unsigned char*)hash, &len, SK);
  // Free allocations
  BIO_free_all(IO);
  EVP_PKEY_free(SK);
  EVP_MD_CTX_destroy(X);
}

char* b64enc(const char* in, char* res, const int bufsz) {
  // Use modified lookup table because today's base-64 standards are different
  // when dealing with JWT
  const char* lut =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
  // get output pointer and size of input
  int n = 0, insz = strlen(in);
  char* rp = res;
  // exit if input buffer is too small but we made large buffers for our test so
  // this shouldn't happen.
  if ((insz / 3) * 4 + 2 > bufsz) {
    return NULL;
  }
  // wipe out output buffer
  memset(res, 0, bufsz);
  while (n < insz) {
    unsigned long d = 0, n2 = 0, gotbytes = 0;
    // shove up to 3 characters into a 32-bit buffer (defined as unsigned long
    // d)
    while (n2 < 3 && n < insz) {
      d = (d << 8) + in[n];
      n++;
      n2++;
      gotbytes++;
    }
    // Keep shoving in binary 0's until 24 bits are shifted in.
    while (n2 < 3) {
      d = (d << 8);
      n2++;
    }
    // Output is stored backwards so we make it forwards but only giving 6 bits
    // (hence anding with 0x3F)
    *rp++ = lut[(d >> 18) & 0x3F];
    *rp++ = lut[(d >> 12) & 0x3F];
    if (gotbytes >= 2) {
      *rp++ = lut[(d >> 6) & 0x3F];
    }  // input bytes >= 2 means 3 bytes in base64
    if (gotbytes >= 3) {
      *rp++ = lut[d & 0x3F];
    }  // input bytes >= 3 means 4 bytes in base64
  }
  return res;
}

int main() {
  // Setup our header and claims for JWT
  char* jwtheader = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
  char* claims = "{\"scope\":\"https://www.example.com/auth\"}";
  // set char array size of each element
  int bufsz = 2048;
  // feed each char array from ssl array to not make memory fragments
  char ssl[11000], *tmp2 = ssl, *tmp = ssl + bufsz,
                   *headerdotclaims = ssl + (bufsz * 2),
                   *sha256val = ssl + (bufsz * 3), *result = ssl + (bufsz * 4);
  // and erase the whole space in ONE operation
  memset(ssl, 0, 10999);
  // Base64 encode JWT values and combine them with a dot.
  sprintf(headerdotclaims, "%s%c%s", b64enc(jwtheader, tmp2, bufsz - 1), '.',
          b64enc(claims, tmp, bufsz - 1));
  // Get SHA256 value of above. (apparently never working)
  getsha(headerdotclaims, sha256val);
  // Add a dot and the base64 encoded version to the result
  sprintf(result, "%s%c%s", headerdotclaims, '.',
          b64enc(sha256val, tmp, bufsz - 1));
  // and show it
  printf("%s", result);
}

请问我的代码中存在哪些问题,导致无法生成符合要求的JWT?


内容的提问来源于stack exchange,提问作者mike_s

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:15:02