Подписать / зашифровать документ EDIFACT - искаженный - C#
Я должен отправить сообщение EDI правительственному органу, которое подписано / зашифровано особым образом.
Согласно https://docs.google.com/document/d/1xOxsZG7nCXdd3ucFKJObheW4G6kFwflGFkzURS_haTY/edit?usp=sharing
Я пытаюсь этот код, но зашифрованный S/MIME неправильно отформатирован в соответствии с правительственным шлюзом.
Ответ по электронной почте от них:
Код ошибки, который я получаю, является ошибкой дешифрования.
Сначала вы должны были подписать свое EDI-сообщение, используя сертификат Gatekeeper. Это создает S/MIME-объект. Мы называем это "подписанным" S/MIME .
Затем вы берете свой подписанный блоб и шифруете его с помощью сертификата таможенного шлюза, загруженного с нашего грузового веб-сайта.
Это создает другой S/MIME, который мы называем "зашифрованным" S/MIME .
Я подписываю и шифрую, используя правильные сертификаты шифрования.
Также пробовал сторонние библиотеки ActiveUp и Chilkat, но пока безрезультатно.
Любая помощь в интерпретации таможенной спецификации и корректировке, где я мог ошибиться, очень ценится. Я работаю над этим вопросом больше недели.
public static void SendEmail(string ediMsg, string clientCertificatePath,
string clientCertificatePassword, string sender, string receiver, string subject, SmtpClient smtp,
string customsCertificatePath)
{
//Load the certificate
X509Certificate2 EncryptCert = new X509Certificate2(customsCertificatePath);
X509Certificate2 SignCert =
new X509Certificate2(clientCertificatePath, clientCertificatePassword);
//Build the body into a string
StringBuilder Message = new StringBuilder();
ediMsg = "UNB+IATB:1+6XPPC+LHPPC+940101:0950+1' ...";
/*The EDI document is first formatted as a MIME message [MIME],
* as the EDI Document may contain special characters, non-printable ASCII and binary data. */
byte[] arrayToEncode = System.Text.Encoding.UTF8.GetBytes(ediMsg);
ediMsg = Convert.ToBase64String(arrayToEncode);
/*Within the MIME message, the Content-Transfer-Encoding header must be either “quoted-printable”
* or “base64”, and the Content-Type header should be set to “Application/EDIFACT”. */
Message.AppendLine("Content-Type: Application/EDIFACT");
Message.AppendLine("Content-Transfer-Encoding: base64");
//The file name of the attachment for inbound e-mails (to Customs) must be the same as the Subject Line
//(section 3.3) with the .edi suffix.
Message.AppendLine("Content-Disposition: attachment; filename=\"" + subject + ".edi\"");
/*I have tried this with
* (a) the raw ediMsg,
* (b) the base64 version of (a)
* (c) quoted-printable version of (a)
* (d) base64 version of (c)
*/
Message.AppendLine(ediMsg);
//Text must not be included in the body of the e-mail. EDI documents must be sent as an attachment.
//Convert the body to bytes
byte[] BodyBytes = Encoding.UTF8.GetBytes(Message.ToString());
//sign
var signedBytes = SignMsg(BodyBytes, SignCert);
//Build the e-mail body bytes into a secure envelope
EnvelopedCms Envelope = new EnvelopedCms(new ContentInfo(signedBytes));
CmsRecipient Recipient = new CmsRecipient(
SubjectIdentifierType.IssuerAndSerialNumber, EncryptCert);
Envelope.Encrypt(Recipient);
byte[] EncryptedBytes = Envelope.Encode();
//Create the mail message
MailMessage Msg = new MailMessage();
Msg.To.Add(new MailAddress(receiver));
Msg.From = new MailAddress(sender);
Msg.Subject = subject;
//Attach the encrypted body to the email as and ALTERNATE VIEW
MemoryStream ms = new MemoryStream(EncryptedBytes);
AlternateView av =
new AlternateView(ms,
"application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
Msg.AlternateViews.Add(av);
//SmtpClient smtp = new SmtpClient(MailServer, 25);
//send the email
smtp.Send(Msg);
}
1 ответ
Я не уверен, что проблемы, на которые я собираюсь указать, - это проблема, но, возможно, их стоит рассмотреть...
Первый, Convert.ToBase64String(arrayToEncode);
не переносит строки, как это необходимо в MIME. Вам нужно использовать этот вариант с Base64FormattingOptions.InsertLineBreaks
,
Во-вторых, я не знаю, что делает SignMsg(), но убедитесь, что вы добавили правильные заголовки Content-Type, Content-Transfer-Encoding и (возможно) Content-Disposition. Тип контента должен быть application/pkcs7-mime; smime-type=signed-data; name=smime.p7s
и Content-Transfer-Encoding должен быть base64
как только вы закодировали в base64 данные.
В-третьих, заголовок Content-Type, который вы дали зашифрованной внешней части, неверен. Так должно быть application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m
,
В-четвертых, убедитесь, что зашифрованные данные кодируются в base64 и что AlternativeView получает кодировку Content-Transfer-Encoding of base64
,
Я не уверен, что добавление его в качестве альтернативного представления обязательно сработает или нет, я должен был бы увидеть сгенерированный MIME, чтобы быть уверенным.
Что-то, что вы могли бы рассмотреть вместо использования IP*Works, который является платным, - это моя библиотека с открытым исходным кодом под названием MimeKit, которая уже поддерживает генерацию сообщений S/MIME. У меня также есть библиотека под названием MailKit, которая поддерживает SMTP, который вы, похоже, используете.
Обе библиотеки легко доступны через NuGet: MimeKit и MailKit
Что бы вы сделали, это что-то вроде этого:
// Note: if the email addresses do not match the certificates, you can
// use a SecureMailboxAddress instead, which allows you to specify the
// Fingerprint (aka Thumbprint) of the certificate to use for signing
// or encrypting.
var recipient = new MailboxAddress ("Receiver Name", "receiver@example.com");
var sender = new MailboxAddress ("Sender Name", "sender@example.com");
var message = new MimeMessage ();
message.To.Add (recipient);
message.From.Add (sender);
message.Subject = subject;
// create the application/edifact MIME part
var edifact = new MimePart ("application", "edifact");
// set the filename of the MIME part (adds a Content-Disposition header
// if not already present)
edifact.FileName = subject + ".edi";
// create the content stream of the MIME part
var content = new MemoryStream (Encoding.UTF8.GetBytes (ediMsg), false);
// set the content of the MIME part (we use ContentEncoding.Default because
// it is not encoded... yet)
edifact.ContentObject = new ContentObject (content, ContentEncoding.Default);
// encode the content using base64 *and* set the Content-Transfer-Encoding header
edifact.ContentTransferEncoding = ContentEncoding.Base64;
using (var ctx = new TemporarySecureMimeContext ()) {
ctx.Import (clientCertificatePath, clientCertificatePassword);
ctx.Import (customsCertificatePath);
// sign and then encrypt the edifact part and then set the result as the
// message body.
message.Body = ApplicationPkcs7Mime.SignAndEncrypt (ctx, sender,
DigestAlgorithm.Sha1, new [] { recipient }, edifact);
}
// MailKit's SMTP API is very similar to System.Net.Mail's SmtpClient API,
// so that shouldn't pose a problem.