| /* |
| * Copyright 2014 Google Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Utility class to parse and verify raw {@link SecureMessage} protos. |
| // Verifies the signature on the message, and decrypts "signcrypted" messages |
| // (while simultaneously verifying the signature). |
| // |
| // @see RawSecureMessageBuilder |
| |
| #include "securemessage/raw_secure_message_parser.h" |
| |
| #include "securemessage/secure_message_wrapper.h" |
| #include "securemessage/util.h" |
| |
| using std::unique_ptr; |
| |
| namespace securemessage { |
| |
| unique_ptr<string> RawSecureMessageParser::ParseSignedCleartextMessage( |
| const string& signature, |
| const string& header_and_body, |
| const CryptoOps::Key& verification_key, |
| CryptoOps::SigType sig_type, |
| const string& associated_data) { |
| |
| // suppress_associated_data is always false signed cleartext |
| if (VerifyHeaderAndBody(signature, header_and_body, verification_key, |
| sig_type, CryptoOps::EncType::NONE, associated_data, |
| false)) { |
| return unique_ptr<string>(new string(header_and_body)); |
| } else { |
| return nullptr; |
| } |
| } |
| |
| unique_ptr<string> RawSecureMessageParser::ParseSignCryptedMessage( |
| const string& signature, |
| const string& header_and_body, |
| const CryptoOps::Key& verification_key, |
| CryptoOps::SigType sig_type, |
| const CryptoOps::SecretKey& decryption_key, |
| CryptoOps::EncType enc_type, |
| const string& associated_data) { |
| if (enc_type == CryptoOps::EncType::NONE) { |
| Util::LogError("Not a signcrypted message"); |
| return nullptr; |
| } |
| |
| bool tagRequired = CryptoOps::TaggedPlaintextRequired( |
| verification_key, sig_type, decryption_key); |
| if (!VerifyHeaderAndBody(signature, header_and_body, verification_key, |
| sig_type, enc_type, associated_data, tagRequired)) { |
| return nullptr; |
| } |
| |
| unique_ptr<string> header = |
| SecureMessageWrapper::ParseInternalHeader(header_and_body); |
| unique_ptr<string> iv = |
| SecureMessageWrapper::ParseHeaderIv(header_and_body); |
| unique_ptr<string> body = |
| SecureMessageWrapper::ParseBody(header_and_body); |
| |
| if (header == nullptr || iv == nullptr || body == nullptr) { |
| Util::LogError("Header and body missing some fields"); |
| return nullptr; |
| } |
| |
| unique_ptr<string> raw_decrypted_body = |
| CryptoOps::Decrypt(decryption_key, enc_type, *iv, *body); |
| |
| if (raw_decrypted_body == nullptr) { |
| Util::LogError("Failed to decrypt body"); |
| return nullptr; |
| } |
| |
| if (!tagRequired) { |
| // No tag expected, so we're all done |
| return SecureMessageWrapper::BuildHeaderAndBody(*header, |
| *raw_decrypted_body); |
| } |
| |
| // Verify the tag that binds the ciphertext to the header, and remove it |
| bool binding_is_verified = false; |
| unique_ptr<string> expected_tag = |
| CryptoOps::Digest(*header + associated_data); |
| if (expected_tag == nullptr) { |
| Util::LogError("Error computing expected tag"); |
| return nullptr; |
| } |
| |
| if (raw_decrypted_body->length() >= CryptoOps::kDigestLength) { |
| unique_ptr<ByteBuffer> actual_tag = |
| ByteBuffer(*raw_decrypted_body).SubArray(0, CryptoOps::kDigestLength); |
| |
| if (actual_tag != nullptr && actual_tag->Equals(ByteBuffer(*expected_tag))) { |
| binding_is_verified = true; |
| } |
| } |
| if (!binding_is_verified) { |
| Util::LogError("Signature exception"); |
| return nullptr; |
| } |
| |
| unsigned int body_len = static_cast<unsigned int>(raw_decrypted_body->size()) |
| - CryptoOps::kDigestLength; |
| |
| // Remove the tag. |
| unique_ptr<ByteBuffer> body_bytes = |
| ByteBuffer(*raw_decrypted_body).SubArray(CryptoOps::kDigestLength, |
| body_len); |
| |
| if (body_bytes == nullptr) { |
| Util::LogError("Invalid body length"); |
| return nullptr; |
| } |
| |
| return SecureMessageWrapper::BuildHeaderAndBody(*header, |
| body_bytes->String()); |
| } |
| |
| bool RawSecureMessageParser::VerifyHeaderAndBody( |
| const string& signature, |
| const string& header_and_body, |
| const CryptoOps::Key& verification_key, |
| CryptoOps::SigType sig_type, |
| CryptoOps::EncType enc_type, |
| const string& associated_data, |
| bool suppress_associated_data /* in case it is in the tag instead */) { |
| |
| string signed_data = header_and_body; |
| if (!suppress_associated_data) { |
| signed_data.append(associated_data); |
| } |
| bool verified = |
| CryptoOps::Verify(sig_type, verification_key, signature, signed_data); |
| |
| unique_ptr<string> header = |
| SecureMessageWrapper::ParseHeader(header_and_body); |
| |
| if (header == nullptr) { |
| Util::LogError("message must have header"); |
| return nullptr; |
| } |
| |
| // Does not return early in order to avoid timing attacks |
| verified &= SecureMessageWrapper::GetSigScheme(sig_type) == |
| SecureMessageWrapper::GetSignatureScheme(*header); |
| verified &= SecureMessageWrapper::GetEncScheme(enc_type) == |
| SecureMessageWrapper::GetEncryptionScheme(*header); |
| verified &= associated_data.length() == |
| SecureMessageWrapper::GetAssociatedDataLength(*header); |
| |
| // Check that either a decryption operation is expected, or no DecryptionKeyId |
| // is set. |
| verified &= enc_type != CryptoOps::EncType::NONE || |
| !SecureMessageWrapper::HasDecryptionKeyId(*header); |
| |
| // If encryption was used, check that either we are not using a public key |
| // signature or a VerificationKeyId was set (as is required for public key |
| // based signature + encryption). |
| verified &= enc_type != CryptoOps::EncType::NONE || |
| CryptoOps::IsPublicKeyScheme(sig_type) || |
| !SecureMessageWrapper::HasVerificationKeyId(*header); |
| |
| return verified; |
| } |
| |
| // Constructor and Destructor are never used |
| RawSecureMessageParser::RawSecureMessageParser() {} |
| RawSecureMessageParser::~RawSecureMessageParser() {} |
| |
| } // namespace securemessage |