gpt4 book ai didi

CMS (PKCS#7) 收件人信息

转载 作者:太空宇宙 更新时间:2023-11-04 00:06:41 28 4
gpt4 key购买 nike

我实际上正在研究一个应该从 PKCS7 mime 加密消息中提取 RecipientInfo 的函数。我想这样做的原因是,我想获取邮件加密的所有邮件地址(或至少是 keyids/指纹)。

嗯 - 我尝试了一些东西并创建了这样的东西(indata 是一个 *.p7m 附件内容,indata_len 是 indata 的 strlen):

char *indata;
int indata_len, i;
PKCS7 *p7 = NULL;
BIO *bcont = NULL;
CMS_ContentInfo *cms = NULL;
STACK_OF(CMS_RecipientInfo) *recipients = NULL;
CMS_RecipientInfo *recip = NULL;
BIO *encMessage = BIO_new(BIO_s_mem());
if (encMessage == NULL) {
goto clean_exit;
}

if(!BIO_write(encMessage, indata, indata_len)) {
goto clean_exit;
}

cms = SMIME_read_CMS(encMessage,NULL);
if (cms == NULL ) {
goto clean_exit;
}

recipients = CMS_get0_RecipientInfos(cms);
if (recipients == NULL) {
goto clean_exit;
}

for (i=0; i< sk_CMS_RecipientInfo_num(recipients); i++) {
recip = sk_CMS_RecipientInfo_value(recipients, i);
if( recip == NULL || CMS_RecipientInfo_type(recip) != CMS_RECIPINFO_TRANS ) {
continue;
}

int r;
ASN1_OCTET_STRING **keyid;
X509_NAME **issuer;
ASN1_INTEGER **sno;

r = CMS_RecipientInfo_ktri_get0_signer_id(recip, keyid, issuer, sno);
if (!r) {
continue;
}

printf("Key: %s\n", keyid);
}

我没有得到任何错误(使用 ERR_get_error() 检查)但是 keyid、issuer 和 sno 保持为“null”,以上代码的输出是:

Key: (null)

所以我的问题是,是否有可能获取加密消息的信息,或者我这边的推理是否存在错误?

如果有可能获得该数据,有人可以给我提示吗?如果不可能,那么检查用于解密的私钥的默认(最佳)方法是什么。由于单个用户可以有多个 S/Mime 证书/ key 。例如。创建新 key ,因为旧 key 丢失或只是从提供商那里获得新的证书/ key 组合,...恕我直言,如果消息真的很大,遍历所有键可能需要一些时间。

最好的问候,最大

最佳答案

我不知道如何修复你的代码,但我有几个 openssl 命令和一个 python 脚本来解决你的任务:

您可以运行以下命令来获取所有序列号的列表加密文件 MYMAIL 中的收件人 key :

openssl smime -pk7out -inform DER -in MYMAIL \
| openssl pkcs7 -noout -print \
| grep serial

这会将序列号打印为所有收件人的十进制数字,即文件 MYMAIL 已为其加密的证书的序列号。对于给定的证书文件 CERTFILE.0,命令

openssl x509 -in CERTFILE.0 -serial -noout

将其序列号打印为十六进制数。现在,您可以将您拥有的证书的序列号与MYMAIL中提到的序列号结合起来。

我写了一个执行此操作的 python 脚本,可用于替换默认的 smime_decrypt_command在 mutt 中,这样在解密电子邮件时,会选择正确的私钥进行解密:https://github.com/t-wissmann/dotfiles/blob/master/utils/smime-recipient-list.py对于 url 中断的情况,我将在下面粘贴整个脚本。

#!/usr/bin/env python3
"""
Given an smime encrypted file and some smime certificates,
tell for which of the smime certificates, the encrypted file has been
encrypted for.
"""

import argparse
import os
import re
import subprocess
import sys
import textwrap

class Openssl:
def __init__(self, openssl_command):
self.openssl_command = openssl_command

def get_certificate_serial_number(self, certificate_file):
"""Given a certificate_file filepath, return its serial number as an int"""
command = [self.openssl_command, 'x509', '-in', certificate_file, '-serial', '-noout']
proc = subprocess.run(command, stdout=subprocess.PIPE)
# output should be of the form 'serial=HEXADECIMALNUMBER'
try:
return int(proc.stdout.decode().replace('serial=', ''), 16)
except ValueError:
print("Can not read file: {}".format(certificate_file), file=sys.stderr)

def smime_pk7out(self, encrypted_file):
"""run smime -pk7out, return its output"""
command = [self.openssl_command, 'smime', '-pk7out']
command += ['-inform', 'DER', '-in', encrypted_file]
proc = subprocess.run(command, stdout=subprocess.PIPE)
return proc.stdout.decode()

def pkcs7_serial_numbers(self, pk7buf):
"""extract all serial numbers via openssl pkcs7 -noout -print"""
command = [self.openssl_command, 'pkcs7', '-noout', '-print']
proc = subprocess.run(command, stdout=subprocess.PIPE, text=True, input=pk7buf)
for match in re.finditer('serial: ([0-9]+)', proc.stdout):
yield int(match.group(1))

def list_recipient_serial_numbers(self, encrypted_file):
"""Do essentially:
openssl smime -pk7out -inform DER -in MYMAIL \
| openssl pkcs7 -noout -print \
| grep serial
"""
pk7out = self.smime_pk7out(encrypted_file)
return list(self.pkcs7_serial_numbers(pk7out))

def smime_decrypt(self, private_key, certificate, filepath, passin='stdin'):
"""encrypt the given filepath and print to stdout"""
command = [self.openssl_command, 'smime', '-decrypt', '-passin', passin]
command += ['-inform', 'DER', '-in', filepath]
command += ['-inkey', private_key]
command += ['-recip', certificate]
subprocess.run(command)

def main():
"""main"""
description = "Detect recipients of smime encrypted files"
epilog = textwrap.dedent(r"""
E.g. you can decrypt an email with the command that picks the
private key automatically:

{} \
--passin stdin --decrypt \
--private-key ~/.smime/keys/* \
-- mymail ~/.smime/certificates/*

If you use mutt, you can set

set smime_decrypt_command="\
~/path/to/smime-recipient-list.py --passin stdin --decrypt \
--private-key ~/.smime/keys/* \
-- %f ~/.smime/certificates/KEYPREFIX.*"

where KEYPREFIX is the prefix of your key (i.e. without the .0 or .1 suffix).
""".format(sys.argv[0]))
parser = argparse.ArgumentParser(
description=description,
epilog=epilog,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('encryptedfile', help='the encrypted file')
parser.add_argument('certificates',
nargs='+',
help='the smime certificate files')
parser.add_argument('--openssl', default='openssl', help='openssl command name')
parser.add_argument('--list-serials', action='store_true',
help='list serial numbers of certifacts')
parser.add_argument('--print-path', action='store_true',
help='print path of recipient certificates')
parser.add_argument('--private-keys', nargs='*', default=[], help='private keys for decrypt')
parser.add_argument('--decrypt', action='store_true',
help='decrypt using one of the private keys passed.\
the key must have the same file name as the certificate.')
parser.add_argument('--passin', default='stdin',
help='default openssl -passin parameter for decrypt')
args = parser.parse_args()
openssl = Openssl(args.openssl)

# get the serial number of every smime-certfile:
serialnum2cert = {}
for i in args.certificates:
serialnum2cert[openssl.get_certificate_serial_number(i)] = i
if args.list_serials:
for serialnum, keyfile in serialnum2cert.items():
print("{} --> {}".format(keyfile, serialnum))
recipients = openssl.list_recipient_serial_numbers(args.encryptedfile)
if args.print_path or args.decrypt:
matching_keys = []
for i in recipients:
if i in serialnum2cert:
matching_keys.append(serialnum2cert[i])
if args.print_path:
for i in matching_keys:
print(i)
if args.decrypt:
private_keys = {}
for filepath in args.private_keys:
private_keys[os.path.basename(filepath)] = filepath
key_found = None
for fp in matching_keys:
if os.path.basename(fp) in private_keys:
priv_key_path = private_keys[os.path.basename(fp)]
# print("We can use {} and {}".format(priv_key_path, fp))
key_found = (priv_key_path, fp)
if key_found is None:
print("No matching private key found.", file=sys.stderr)
sys.exit(1)
openssl.smime_decrypt(key_found[0], key_found[1],
args.encryptedfile, passin=args.passin)

if __name__ == "__main__":
main()

关于CMS (PKCS#7) 收件人信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21290975/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com