Criptografia e Assinatura Digital Patricia Rabelo [email protected] 1 Multipurpose Internet Mail Extensions (MIME) Norma da internet para o formato das mensagens de correio eletrônico. A grande maioria das mensagens de correio eletrônico são trocadas usando o protocolo SMTP e usam o formato MIME. Dividido em cabeçalho e conteúdo Cabeçalho - identifica o tipo do conteúdo, conjunto de caracteres e codificação Conteúdo – dado a ser transmitido 2 Multipurpose Internet Mail Extensions (MIME) - EXEMPLO Content-type: multipart/mixed; boundary="frontier" MIME-version: 1.0 --frontier Content-type: text/plain Este é o corpo da mensagem. --frontier Content-type: application/octet-stream Content-transfer-encoding: base64 gajwO4+n2Fy4FV3V7zD9awd7uG8/TITP/vIocxXnnf/5mjgQjcipBUL1b3 uyLwAVtBLOP4nV LdIAhSzlZnyLAF8na0n7g6OSeej7aqIl3NIXCfxDsPsY6NQjSvV77j4hWE jlF/aglS6ghfju FgRr+OX8QZMI1OmR4rUJUS7xgoknalqj3HJvaOpeb3CFlNI9VGZYz6 H6zuQBOWZzNB8glwpC --frontier-- 3 Secure Multipurpose Internet Mail extension (S/MIME) S/MIME oferece uma forma segura e consistente de enviar e receber dados no formato MIME Oferece os seguintes serviços: autenticação, integridade da mensagem e não-rejeição da mensagem original e confidencialidade. S/MIME pode ser utilizado por qualquer protocolo que suporte MIME, como HTTP Utilizado nos softwares S/MIME de ConnectSoft, Frontier, FTP Software, Qualcomm, Microsoft, Lotus, Wollongong, Banyan, NCD, SecureWare, VeriSign, Netscape, and Novell. Uma das partes do MIME consiste no blob no formato PKCS#7 Ver RFC 3851: http://www.ietf.org/rfc 4 Secure Multipurpose Internet Mail extension (S/MIME) Tipos de S/MIME: Enveloped-data Signed-data Certs-only Compressed-data (p7m) (p7s) (p7c) (p7z) Headers: MIME type: application/pkcs7-mime parameters: any file suffix: any MIME type: multipart/signed parameters: protocol="application/pkcs7-signature" file suffix: any MIME type: application/octet-stream parameters: any file suffix: p7m, p7s, p7c, p7z 5 S/Mime – Enveloped data Mensagem criptografada Tipo: “enveloped- data” extensão:".p7m". Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=smime.p7m rfvbnj756tbBghyHhHUujhJhjH77n8HHGT9HG4VQpfyF467GhIGfHfYT6 7n8HHGghyHhHUujhJh4VQpfyF467GhIGfHfYGTrfvbnjT6jH7756tbB9H f8HHGTrfvhJhjH776tbB9HG4VQbnj7567GhIGfHfYT6ghyHhHUujpfyF4 0GhIGfHfQbnj756YT64V 6 S/Mime – Signed data Mensagem assinada Tipo: signed-data Conteúdo inserido no pkcs#7 Extensão: “.p7m” Content-Type: application/pkcs7-mime; smime-type=signed-data; name=smime.p7m Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=smime.p7m 567GhIGfHfYT6ghyHhHUujpfyF4f8HHGTrfvhJhjH776tbB9HG4VQbnj7 77n8HHGT9HG4VQpfyF467GhIGfHfYT6rfvbnj756tbBghyHhHUujhJhjH HUujhJh4VQpfyF467GhIGfHfYGTrfvbnjT6jH7756tbB9H7n8HHGghyHh 6YT64V0GhIGfHfQbnj75 7 S/Mime – Certs Only data Mensagem para transmitir certificados Tipo: “certs-only” Extensão: “.p7c” 8 S/Mime – Compressed data Mensagem compactada Tipo: “compressed-data” Extensão: “.p7z” Content-Type: application/pkcs7-mime; smime-type=compresseddata; name=smime.p7z Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=smime.p7z rfvbnj756tbBghyHhHUujhJhjH77n8HHGT9HG4VQpfyF467GhIGf HfYT6 7n8HHGghyHhHUujhJh4VQpfyF467GhIGfHfYGTrfvbnjT6jH7756 tbB9H f8HHGTrfvhJhjH776tbB9HG4VQbnj7567GhIGfHfYT6ghyHhHUuj pfyF4 0GhIGfHfQbnj756YT64V 9 Segurança via WEB Desenvolver práticas de segurança que permita o acesso da chave privada para o usuário (assinante/assinatura ou destinatário/criptografia), porém que a proteja do acesso pelo servidor web. 10 PKCS Public Key Cryptography Standards PKCS #1 – 2.1RSA Cryptography StandardSee RFC 3447. Defines the mathematical properties and format of RSA public and private keys (ASN.1-encoded in clear-text), and the basic algorithms and encoding/padding schemes for performing RSA encryption, decryption, and producing and verifying signatures. PKCS #2 – WithdrawnNo longer active. Covered RSA encryption of message digests, but was merged into PKCS #1 PKCS #3 – 1.4Diffie-Hellman Key Agreement StandardA cryptographic protocol that allows two parties that have no prior knowledge of each other to jointly establish a shared secret key over an insecure communications channel. PKCS #4 – WithdrawnNo longer active. Covered RSA key syntax, but was merged into PKCS #1. PKCS #5 – 2.0Password-based Encryption StandardSee RFC 2898 and PBKDF2. PKCS #6 – 1.5Extended-Certificate Syntax StandardDefines extensions to the old v1 X.509 certificate specification. Obsoleted by v3 of the same. PKCS #7 – 1.5Cryptographic Message Syntax StandardSee RFC 2315. Used to sign and/or encrypt messages under a PKI. Used also for certificate dissemination (for instance as a response to a PKCS#10 message). Formed the basis for S/MIME, which is now based on RFC 3852, an updated Cryptographic Message Syntax Standard (CMS). Often used for single sign-on. 11 PKCS Public Key Cryptography Standards PKCS #8 – 1.2Private-Key Information Syntax Standard.Used to carry private certificate keypairs (encrypted or unencrypted). PKCS #9 - 2.0Selected Attribute TypesDefines selected attribute types for use in PKCS #6 extended certificates, PKCS #7 digitally signed messages, PKCS #8 private-key information, and PKCS #10 certificate-signing requests. PKCS #10 - 1.7Certification Request StandardSee RFC 2986. Format of messages sent to a certification authority to request certification of a public key. See certificate signing request. PKCS #11 - 2.20Cryptographic Token Interface (Cryptoki)An API defining a generic interface to cryptographic tokens (see also Hardware Security Module). Often used for single sign-on and smartcard [1]. PKCS #12 - 1.0Personal Information Exchange Syntax StandardDefines a file format commonly used to store private keys with accompanying public key certificates, protected with a password-based symmetric key. PFX is a predecessor to PKCS#12. This is a container format that can contain multiple embedded objects, e.g. multiple certificates. Usually protected/encrypted with a password. Can be used as a format for the Java key store. Can be used by Tomcat, but NOT by Apache. PKCS #13 – Elliptic Curve Cryptography Standard(Under development) PKCS #14 – Pseudo-random Number Generation(Under development.) PKCS #15 – 1.1Cryptographic Token Information Format StandardDefines a standard allowing users of cryptographic tokens to identify themselves to applications, independent of the application's Cryptoki implementation (PKCS #11) or other API. RSA has relinquished ICcard-related parts of this standard to ISO/IEC 7816-15 [2]. 12 Cryptographic Message Syntax (CMS) RFC3851 O CMS descreve uma sintaxe para proteção de dados, tanto para assinatura digital quanto criptografia. Essa sintaxe permite encapsulamento, dados encapsulados podem estar presentes de forma aninhada. Derivado do formato PKCS#7 versão 1.5 Formato expresso em ASN.1 [X.208-88], com a codificação BER (Basic Encoded Rules) [X.209-88] ASN.1 – linguagem que define as palavras reservados do formato BER – codificação binária que identifica o tamanho de cada parte da informação decodificação em um único passo. 13 Cryptographic Message Syntax (CMS) RFC3851 id-ct-contentInfo OBJECT IDENTIFIER ::= { iso(1) memberbody(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) ct(1) 6 } ContentInfo ::= SEQUENCE { contentType ContentType, content [0] EXPLICIT ANY DEFINED BY contentType } ContentType ::= OBJECT IDENTIFIER 14 Cryptographic Message Syntax (CMS) Content Type pode identificar o tipo do conteúdo com os seguintes valores: Dados (id-data): Assinatura (id-signedData): OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 5 } Dado criptografado (id-encryptedData): OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 } Hash de dados (Digested-data): OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 } Criptografia (id-envelopedData): OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 } OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 } Dado Autenticado (id-ct-authData): OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1) 2 } 15 Processo - assinatura 1. 2. 3. 4. O digest da mensagem a ser transmitida é calculado utilizando o algoritmo de assinatura especificado por cada assinante. Para cada assinante, o digest calculado é criptografado pela chave privada do assinante. O valor do digest criptografado e demais informações específicas de cada assinante são inseridas no SignerInfo value: certificados, CRLs, etc. Os SignerInfo de todos os assinante são coletados no SignedData. 16 Processo – Validação de assinatura 1. 2. 3. O receptor decifra o digest da mensagem de cada assinante utilizando a chave pública do respectivo assinante. A chave pública pode ser obtida a partir de certificados que pode estar eventualmente no SignerInfo do assinante ou a partir de uma fonte confiável do receptor dado que o receptor tenha o “issuer distinguished name” e “issuer-specific serial number” do certificado do assinante. O digest do mensagem é calculado de forma independente pelo receptor utilizando o algoritmo de cada assinante. Em seguida, o valor do digest calculado é comparado com o valor do digest decifrado. Se a comparação for bem sucedida, a assinatura é válida. 17 CMS – Signed Data RFC 3852 SignedData ::= SEQUENCE { version CMSVersion, digestAlgorithms DigestAlgorithmIdentifiers, encapContentInfo EncapsulatedContentInfo, certificates [0] IMPLICIT CertificatesSet OPTIONAL, crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, signerInfos SignerInfos } DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier DigestAlgorithmIdentifier ::= AlgorithmIdentifier EncapsulatedContentInfo ::= SEQUENCE { eContentType ContentType, eContent [0] EXPLICIT OCTET STRING OPTIONAL } ContentType ::= OBJECT IDENTIFIER CertificatesSet ::= SET OF ExtendedCertificateOrCertificate ExtendedCertificateOrCertificate ::= CHOICE { certificate Certificate, -- X.509 extendedCertificate [0] IMPLICIT ExtendedCertificate } CertificateRevocationLists ::= SET OF CertificateRevocationList SignerInfos ::= SET OF SignerInfo 18 CMS – Signed Data SignerInfo ::= SEQUENCE { version CMSVersion, sid SignerIdentifier, digestAlgorithm DigestAlgorithmIdentifier, signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, signatureAlgorithm SignatureAlgorithmIdentifier, signature SignatureValue, unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } RFC 3852 SignerIdentifier ::= CHOICE { issuerAndSerialNumber IssuerAndSerialNumber, subjectKeyIdentifier [0] SubjectKeyIdentifier } SignedAttributes ::= SET SIZE (1..MAX) OF Attribute UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute Attribute ::= SEQUENCE { attrType OBJECT IDENTIFIER, attrValues SET OF AttributeValue } AttributeValue ::= ANY SignatureValue ::= OCTET STRING 19 CMS – Signed Data RFC 3852 Version – varia de acordo com o que foi incluído na mensagem: Formatos dos certificados que estão presentes Formatos das CRLS que estão presentes Tipo do conteúdo Versão do formato do certificado Versão do formato do SignerInfo Content – opcional, quando ausente temos uma assinatura externa AlgorithmIdentifier – pode ser MD2, MD5 Certificates – conjunto de certificados no formato PKCS #6 e certificados X.509. Este conjunto deve ser suficiente para validar toda a cadeia de certificados de cada assinante. CRLs - certificate revocation list (CRL) consiste na lista de números seriais de certificados que foram revogados ou que não estão válidos e, consequentemente, não devem ser confiáveis. Há 2 status de revogação (ver RFC 3280): revoked (permanente) ou hold (temporário). SignedAttributes - Atributos que são assinados junto com a mensagem, exemplos: data e hora da assinatura. SMIME capabilities – preferências para comunicação com o receptor SMIME encription key preference Id message digest Id content type 20 Processo – Criptografia Uma chave para criptografar o conteúdo é gerada aleatoriamente (content-encryption key). 2. Para cada destinatário, a chave aleatória pode ser criptografada: 1. • • • • pela chave pública do destinatário e armazenada no seu respectivo KeyTransRecipientInfo; por uma chave simétrica obtida por um acordo entre remetente/destinatário e armazenada no seu respectivo KEyAgreeRecipientInfo por uma chave simétrica previamente obtida(chave de sessão) e armazenada no seu respectivo KEKRecipientInfo; por uma chave derivada de uma senha e armazenada em PasswordRecipientInfo. Para cada destinatário, a chave aleatória criptografa e outras informações específicas do destinatário são armazenadas no RecipientInfo value 4. O conteúdo é criptografado com a chave aleatória gerada. 5. Os registros do RecipientInfo dos destinatários e o conteúdo criptografa são armazenados no EnvelopedData. 3. 21 Processo – Validação de Criptografia 1. 2. 3. O destinatário recebe o EnvelopedData, identifica seu respectivo RecipientInfo e o decifra utilizando sua chave privada O destinatário obtém a chave aleatória gerada (content-encription key). O destinatário decifra o conteúdo utilizando a chave aleatória (content-encription key). 22 CMS – Enveloped Data RFC 3852 EnvelopedData ::= SEQUENCE { version CMSVersion, originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, recipientInfos RecipientInfos, encryptedContentInfo EncryptedContentInfo, unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } OriginatorInfo ::= SEQUENCE { certs [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT RevocationInfoChoices OPTIONAL } RecipientInfos ::= SET OF RecipientInfo 23 CMS – Enveloped Data RFC 3852 EncryptedContentInfo ::= SEQUENCE { contentType ContentType, contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL } EncryptedContent ::= OCTET STRING RecipientInfo ::= SEQUENCE { ktri KeyTransRecipientInfo, kari [1] KeyAgreeRecipientInfo, kekri [2] KEKRecipientInfo, pwri [3] PasswordRecipientinfo, ori [4] OtherRecipientInfo } EncryptedKey ::= OCTET STRING UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute 24 Exemplo utilizando CRIPTO API - C http://msdn.microsoft.com/en-us/library/cc527452.aspx 25 //------------------------------------------------------------------// Copyright (c) Microsoft Corporation. All rights reserved. ... //------------------------------------------------------------------// Define the name of a certificate subject. The definition of SIGNER_NAME must be changed to the name of // the subject of a certificate that has access to a private key. That certificate must have either the // CERT_KEY_PROV_INFO_PROP_ID or CERT_KEY_CONTEXT_PROP_ID property set for the context to // provide access to the private signature key. #define SIGNER_NAME L"Insert_signer_name_here" // Define the name of the store where the needed certificate// #define CERT_STORE_NAME L"MY" can be found. //------------------------------------------------------------------int _tmain(int argc, _TCHAR* argv[]) { CRYPT_DATA_BLOB SignedMessage; if(SignMessage(&SignedMessage)) { CRYPT_DATA_BLOB DecodedMessage; if(VerifySignedMessage(&SignedMessage, &DecodedMessage)) free(DecodedMessage.pbData); free(SignedMessage.pbData); } _tprintf(TEXT("Press any key to exit.")); } 26 //------------------------------------------------------------------// SignMessage bool SignMessage(CRYPT_DATA_BLOB *pSignedMessageBlob) { //inicialization ... // Initialize the output pointer. pSignedMessageBlob->cbData = 0; pSignedMessageBlob->pbData = NULL; // The message to be signed. Usually, the message exists somewhere and a pointer is passed to the application. pbMessage = (BYTE*)TEXT("CryptoAPI is a good way to handle security"); // Calculate the size of message. To include the terminating null character, cbMessage = (lstrlen((TCHAR*) pbMessage) + 1) * sizeof(TCHAR); // Create the MessageArray and the MessageSizeArray. const BYTE* MessageArray[] = {pbMessage}; DWORD_PTR MessageSizeArray[1]; MessageSizeArray[0] = cbMessage; // Open the certificate store. if ( ( hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, CERT_STORE_NAME))){ // Get a pointer to the signer's certificate. This certificate must have access to the signer's private key. if(pSignerCert = CertFindCertificateInStore( hCertStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, SIGNER_NAME, NULL)) { ... 27 // Initialize the signature structure. SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA); SigParams.dwMsgEncodingType = MY_ENCODING_TYPE; SigParams.pSigningCert = pSignerCert; SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA; SigParams.HashAlgorithm.Parameters.cbData = NULL; SigParams.cMsgCert = 1; SigParams.rgpMsgCert = &pSignerCert; //incluindo certificado do assinante SigParams.cAuthAttr = 0; SigParams.dwInnerContentType = 0; SigParams.cMsgCrl = 0; SigParams.cUnauthAttr = 0; SigParams.dwFlags = 0; SigParams.pvHashAuxInfo = NULL; SigParams.rgAuthAttr = NULL; // First, get the size of the signed BLOB. if( CryptSignMessage(&SigParams, FALSE, &cbSignedMessageBlob)) 1, MessageArray, MessageSizeArray, NULL, // Allocate memory for the signed BLOB. if((pbSignedMessageBlob = (BYTE*)malloc(cbSignedMessageBlob))) // Get the signed message BLOB. if(CryptSignMessage( &SigParams, FALSE, 1, pbSignedMessageBlob, &cbSignedMessageBlob)) MessageArray, MessageSizeArray, // pbSignedMessageBlob now contains the signed BLOB. fReturn = true; // Clean up and free memory as needed. if(pSignerCert) CertFreeCertificateContext(pSignerCert); if(hCertStore) CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG); return fReturn; 28 //// Verify the message signature. Usually, this would be done in a separate program. bool VerifySignedMessage( CRYPT_DATA_BLOB *pSignedMessageBlob, CRYPT_DATA_BLOB *pDecodedMessageBlob) { bool fReturn = false; DWORD cbDecodedMessageBlob; BYTE *pbDecodedMessageBlob = NULL; CRYPT_VERIFY_MESSAGE_PARA VerifyParams; .... // Initialize the VerifyParams data structure. VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA); VerifyParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE; VerifyParams.hCryptProv = 0; VerifyParams.pfnGetSignerCertificate = NULL; VerifyParams.pvGetArg = NULL; // First, call CryptVerifyMessageSignature to get the length of thebuffer needed to hold the decoded message. if( CryptVerifyMessageSignature( &VerifyParams, 0, pSignedMessageBlob->pbData, pSignedMessageBlob->cbData, &cbDecodedMessageBlob, NULL)) NULL, // Allocate memory for the decoded message. if((pbDecodedMessageBlob = (BYTE*)malloc(cbDecodedMessageBlob))) // Call CryptVerifyMessageSignature again to verify the signature and, if successful, copy the decoded message into the buffer. // This will validate the signature against the certificate in the local store. if(CryptVerifyMessageSignature( &VerifyParams, 0, pSignedMessageBlob->pbData, pSignedMessageBlob->cbData, pbDecodedMessageBlob, &cbDecodedMessageBlob, NULL)) { // emite mensagem "The verified message is \"%s\".\n"), pbDecodedMessageBlob); fReturn = true; } else { // emite mensagem "Verification message failed. \n")); } ... // If the decoded message buffer is still around, it means the function was successful. Copy the pointer and size into the output parameter. if(pbDecodedMessageBlob) { pDecodedMessageBlob->cbData = cbDecodedMessageBlob; pDecodedMessageBlob->pbData = pbDecodedMessageBlob; } return fReturn; } 29