先导入这两个库
<openssl/rand.h>
<openssl/evp.h>

这里使用的openssl加密套件版本是3.0.7

@property (nonatomic, copy) NSString *publicKey;
@property (nonatomic, copy) NSString *privateKey;

主要逻辑代码都写在下面代码了

椭圆曲线(Elliptic Curve,EC)是密码学中非常重要的代数结构。在公钥加密、数字签名、密钥协商、安全多方计算等领域均有非常广泛的应用 本案展示的是 Curve25519、Ed25519

以下案例是我在实际开发过程中使用到的 这个算法是某些大厂中广泛应用到的加密算法

先说下 整个加密算法分为四部

1.本端生成公私钥对
2.根据对方传来的公钥和本端私钥生成共享密钥
3.通过共享密钥去解密对端传来用来校验的数据
4.进行最终的数据签名和验证
   简称ECC算法,是基于数学理论的椭圆曲线来实现的一种“非对称加密”算法。特点:密钥的长度很短,高安全。

第一步生成客户端的公私钥对 因为客户端的秘钥长度要求是64位 所以这里进行base64处理下

- (NSData *)safeBase64EncodingString:(NSString *)str options:(NSInteger)options {
  if ([HWTool isEmptyStr:str]) {
    return [[NSData alloc] init];
  }
  return [[NSData alloc] initWithBase64EncodedString:str options:options];
}

// 生成ECC APP公钥和私钥
- (NSArray *)createPublicAndPrivateKey {
  EVP_PKEY_CTX *ctx;
  EVP_PKEY *evpKey = NULL;
  size_t public_keylen = AES256CBC_KEY_LENGTH;
  size_t private_keylen = AES256CBC_KEY_LENGTH;
  unsigned char *publickey = NULL;
  unsigned char *privatekey = NULL;
  // 初始化 OpenSSL 库
  OpenSSL_add_all_algorithms();
  // 生成私钥和公钥
  ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
  EVP_PKEY_keygen_init(ctx);
  EVP_PKEY_keygen(ctx, &evpKey);
  // 获取公钥原始数据 EVP_PKEY_get_raw_public_key
  if (EVP_PKEY_get_raw_public_key(evpKey, NULL, &public_keylen) != 1) {
    printf("Failed to get raw public key length ");
    return nil;
  }
  publickey = (unsigned char *)malloc(public_keylen);
  if (EVP_PKEY_get_raw_public_key(evpKey, publickey, &public_keylen) != 1) {
    printf("Failed to get raw public key ");
    return nil;
  }
  NSData *publickeyData = [NSData dataWithBytes:publickey length:public_keylen];
  if (!publickeyData) {
    return nil;
  }
}
// 生成手机端公私钥
- (void)createSourePublicKeyAndPrivateKey {
  NSArray *array = [self createPublicAndPrivateKey];
  // 防止越界 加一个判断
  if (array.count >= NUMBER_TWO) {
    // 公钥
    NSData *publicData = array.firstObject;
    self.publicKey = [publicData base64EncodedStringWithOptions:0];
    // 私钥
    NSData *privateData = array.lastObject;
    self.privateKey = [privateData base64EncodedStringWithOptions:0];
  }
}
- (int)sign:(NSString *)sign key:(NSString *)publickKey serverInfo:(NSString *)info {
  // 验证数据
  NSData *oneData =  [[NSData alloc] initWithBase64EncodedString:publicKey options:NSDataBase64DecodingIgnoreUnknownCharacters]
  NSData *twoData =  [[NSData alloc] initWithBase64EncodedString:self.publicKey options:NSDataBase64DecodingIgnoreUnknownCharacters]
  NSMutableData *datas = [[NSMutableData alloc] initWithCapacity:0];
  [datas appendData:oneData];
  [datas appendData:twoData];

  NSData *signData = [HWHomeVisionTools safeBase64EncodingString:sign  options:NSDataBase64DecodingIgnoreUnknownCharacters];
  // ED25519
  NSData *public_key = [HWHomeVisionTools safeBase64EncodingString:info
                               options:NSDataBase64DecodingIgnoreUnknownCharacters];
  BOOL isSuccess = [self verfitySignData:datas key:signData serverInfo:public_key];
  return isSuccess;
}
// 根据对端公钥生成共享密钥
// @param peerKey 对端公钥
- (NSString *)getShareKeyWithPeerKey:(NSString *)peerKey {
  NSData *privateData = [HWHomeVisionTools safeBase64EncodingString:self.privateKey
                                options:NSDataBase64DecodingIgnoreUnknownCharacters];
  NSData *peerData = [HWHomeVisionTools safeBase64EncodingString:peerKey
                              options:NSDataBase64DecodingIgnoreUnknownCharacters];
  NSData *shareData = [self eccPublicSharedKeyWithServerPubKey:peerData appPrivateKey:privateData];
  NSString *shareKeyStr = [shareData base64EncodedStringWithOptions:0];
  if (shareKeyStr.length == NUMBER_ZERO) {
    return @"";
  }
  return shareKeyStr;
}
// 生成ECC APP公钥和私钥
- (NSArray *)createPublicAndPrivateKey {
  EVP_PKEY_CTX *ctx;
  EVP_PKEY *evpKey = NULL;
  size_t public_keylen = AES256CBC_KEY_LENGTH;
  size_t private_keylen = AES256CBC_KEY_LENGTH;
  unsigned char *publickey = NULL;
  unsigned char *privatekey = NULL;
  // 初始化 OpenSSL 库
  OpenSSL_add_all_algorithms();
  // 生成私钥和公钥
  ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
  EVP_PKEY_keygen_init(ctx);
  EVP_PKEY_keygen(ctx, &evpKey);
  // 获取私钥原始数据 EVP_PKEY_get_raw_private_key
  if (EVP_PKEY_get_raw_private_key(evpKey, NULL, &private_keylen) != 1) {
    printf("Failed to get raw private key length ");

  }
  privatekey = (unsigned char *)malloc(private_keylen);
  if (EVP_PKEY_get_raw_private_key(evpKey, privatekey, &private_keylen) != 1) {
    printf("Failed to get raw private key ");
  }
  NSData *privateKeyData = [NSData dataWithBytes:privatekey length:private_keylen];
  if (!privateKeyData) {
    return nil;
  }
  NSArray *dataArray = @[publickeyData, privateKeyData];
  // 释放内存
  EVP_PKEY_free(evpKey);
  evpKey = NULL;
  EVP_PKEY_CTX_free(ctx);
  ctx = NULL;
  memset_s(publickey, public_keylen, 0, public_keylen);
  free(publickey);
  publickey = NULL;
  memset_s(privatekey, private_keylen, 0, private_keylen);
  free(privatekey);
  privatekey = NULL;
  // 清理 OpenSSL 库
  EVP_cleanup();
  return dataArray;
}
// 密钥交换生成共享密钥
- (NSData *)eccPublicSharedKeyWithServerPubKey:(NSData *)serverPubKey appPrivateKey:(NSData *)appPrivateKey {
  if (!serverPubKey || serverPubKey.length == NUMBER_ZERO || !appPrivateKey || appPrivateKey.length ==NUMBER_ZERO) {
    return nil;
  }
  EVP_PKEY_CTX *ctx;
  EVP_PKEY *private_key, *public_key;
  size_t length = AES256CBC_KEY_LENGTH;
  public_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, [serverPubKey bytes], length);
  private_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, [appPrivateKey bytes], length);
  ctx = EVP_PKEY_CTX_new(private_key, NULL);
  EVP_PKEY_derive_init(ctx);
  EVP_PKEY_derive_set_peer(ctx, public_key);
  unsigned char *shared_secret;
  size_t shared_secret_len;
  EVP_PKEY_derive(ctx, NULL, &shared_secret_len);
  shared_secret = (unsigned char *)OPENSSL_malloc(shared_secret_len);
  EVP_PKEY_derive(ctx, shared_secret, &shared_secret_len);
  if (shared_secret == NULL) {
    return nil;
  }
  NSData *data = [NSData dataWithBytes:shared_secret length:length];
  EVP_PKEY_CTX_free(ctx);
  ctx = NULL;
  memset_s(shared_secret, shared_secret_len, 0, shared_secret_len);
  free(shared_secret);
  shared_secret = NULL;
  return data;
}
// 数据验证
- (BOOL)verfitySignData:(NSData *)signData key:(NSData *)publickKey serverInfo:(NSData *)info {
  if (signData.length == NUMBER_ZERO || publickKey.length == NUMBER_ZERO || info.length == NUMBER_ZERO) {
    return nil;
  }
  EVP_PKEY_CTX *ctx;
  EVP_PKEY *public_key;
  size_t length = AES256CBC_KEY_LENGTH;
  // 共享密钥
  public_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, [publickKey bytes], length);
  ctx = EVP_PKEY_CTX_new(public_key, NULL);
  EVP_PKEY_derive_init(ctx);
  BOOL isSuccess = EVP_PKEY_verify(ctx, signData.bytes, signData.length, info.bytes, info.length);
  EVP_PKEY_CTX_free(ctx);
  EVP_PKEY_free(public_key);
  ctx = NULL;
  return isSuccess;
}
IV_LENGTH 为12位偏移量
#pragma mark - AES-GCM256 解密
+ (NSData *)aesGcm256DecryptKey:(NSData *)keyData message:(NSData *)message {
  // 将密文拆分为iv+key
  int inputLength = (int)[message length];
  int decrypuLength = 0;
  NSData *iv = [NSData data];
  if (inputLength > (IV_LENGTH + VERSION_LENGTH)) {
    iv = [message subdataWithRange:NSMakeRange(VERSION_LENGTH, IV_LENGTH)];
    decrypuLength = (int)(inputLength - IV_LENGTH - VERSION_LENGTH);
  }
  NSData *inputData = [message subdataWithRange:NSMakeRange(IV_LENGTH + VERSION_LENGTH, decrypuLength)];
  NSData *cipher = [AESCipher AESGcm256Decrypt:inputData withKey:keyData iv:iv];
  return cipher;
}

#pragma mark - AES-GCM256 加密
+ (NSData *)aesGcm256EncryptKey:(NSData *)keyData message:(NSData *)message {
  NSMutableData *sendData = [[NSMutableData alloc] initWithCapacity:0];
  Byte byte[] = {00}; // 1个字节
  NSData *versionData = [[NSData alloc] initWithBytes:byte length:1];
  [sendData appendData:versionData];
  NSData *ivData = [[NSMutableData alloc] init];
  // 验证随机数
  Byte randomBytes[12];
  int ivResult = SecRandomCopyBytes(kSecRandomDefault, 12, randomBytes);
  // 验证结果返回0表示成功 其他值失败
  if(ivResult == 0) {
   ivData = [[NSMutableData alloc] initWithBytes:randomBytes length:12];
  }
  [sendData appendData:ivData];
  NSData*encrytData = [AESCipher AESGcm256Encrypt:message withKey:keyData iv:ivData];
  [sendData appendData:encrytData];
  return sendData;
}