blob: a781cb7cac50dff45ead264faa73590322b7aea3 [file] [log] [blame]
// 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.
//
///////////////////////////////////////////////////////////////////////////////
// A command-line utility for generating Digital Signatures keys, and creating
// and verifying digital signatures.
//
// The first argument is the operation and it should be one of the following:
// gen-private-key get-public-key sign verify.
// Additional arguments depend on the operation.
//
// gen-private-key
// Generates a new private keyset using the RsaSsaPkcs13072Sha256F4 template.
// It requires 1 additional argument:
// output-file: name of the file for the resulting output
//
// get-public-key
// Extracts a public keyset associated with the given private keyset.
// It requires 2 additional arguments:
// private-keyset-file: name of the file with the private keyset
// output-file: name of the file for the resulting output
//
// sign
// Signs the message using the given private keyset.
// It requires 3 additional arguments:
// private-keyset-file: name of the file with the private keyset
// message-file: name of the file with the message
// output-file: name of the file for the resulting output
//
// verify
// Verifies the signature of the message using the given public keyset.
// It requires 4 additional arguments:
// public-keyset-file: name of the file with the public keyset
// message-file: name of the file with the message
// signature-file: name of the file with the signature
// output-file: name of the file for the resulting output (valid/invalid)
#include <iostream>
#include "digital_signatures/util.h"
#include "tink/signature/signature_key_templates.h"
#include "tink/public_key_sign.h"
#include "tink/public_key_verify.h"
// Prints usage info.
void PrintUsageInfo() {
std::clog << "Usage: operation arguments\n"
<< "where operation is one of the following:\n"
<< " gen-private-key get-public-key sign verify\n"
<< "and, depending on the operation, arguments are:\n"
<< " gen-private-key: output-file\n"
<< " get-public-key: private-keyset-file output-file\n"
<< " sign: private-keyset-file message-file output-file\n"
<< " verify: public-keyset-file message-file signature-file "
<< "output-file" << std::endl;
}
// Generates a new private keyset using the RsaSsaPkcs13072Sha256F4 template
// and writes it to the output file.
void GeneratePrivateKey(const std::string& output_filename) {
std::clog << "Generating a new private keyset.." << std::endl;
auto key_template =
crypto::tink::SignatureKeyTemplates::RsaSsaPkcs13072Sha256F4();
auto new_keyset_handle_result =
crypto::tink::KeysetHandle::GenerateNew(key_template);
if (!new_keyset_handle_result.ok()) {
std::clog << "Generating new keyset failed: "
<< new_keyset_handle_result.status().error_message()
<< std::endl;
exit(1);
}
auto keyset_handle = std::move(new_keyset_handle_result.ValueOrDie());
std::clog << "Writing the keyset to file " << output_filename
<< "..." << std::endl;
Util::WriteKeyset(keyset_handle, output_filename);
}
// Extracts a public keyset associated with the given private keyset
// and writes it to the output file.
void ExtractPublicKey(const std::string& private_keyset_filename,
const std::string& output_filename) {
std::clog << "Extracting a public keyset associated with the private "
<< "keyset from file " << private_keyset_filename << "..."
<< std::endl;
auto private_keyset_handle = Util::ReadKeyset(private_keyset_filename);
auto new_keyset_handle_result =
private_keyset_handle->GetPublicKeysetHandle();
if (!new_keyset_handle_result.ok()) {
std::clog << "Getting the keyset failed: "
<< new_keyset_handle_result.status().error_message()
<< std::endl;
exit(1);
}
auto public_keyset_handle =
std::move(new_keyset_handle_result.ValueOrDie());
std::clog << "Writing the keyset to file " << output_filename
<< "..." << std::endl;
Util::WriteKeyset(public_keyset_handle, output_filename);
}
// Signs the message using the given private keyset
// and writes the signature to the output file.
void Sign(const std::string& keyset_filename,
const std::string& message_filename,
const std::string& output_filename) {
auto keyset_handle = Util::ReadKeyset(keyset_filename);
auto primitive_result =
keyset_handle->GetPrimitive<crypto::tink::PublicKeySign>();
if (!primitive_result.ok()) {
std::clog << "Getting PublicKeySign-primitive from the factory failed: "
<< primitive_result.status().error_message() << std::endl;
exit(1);
}
auto public_key_sign = std::move(primitive_result.ValueOrDie());
std::clog << "Signing message from file " << message_filename
<< " using private keyset from file " << keyset_filename
<< "..." << std::endl;
std::string message = Util::Read(message_filename);
auto sign_result = public_key_sign->Sign(message);
if (!sign_result.ok()) {
std::clog << "Error while signing the message: "
<< sign_result.status().error_message() << std::endl;
exit(1);
}
std::string signature = sign_result.ValueOrDie();
std::clog << "Writing the resulting signature to file " << output_filename
<< "..." << std::endl;
Util::Write(signature, output_filename);
}
// Verifies the signature of the message using the given public keyset
// and writes the result to the output file.
void Verify(const std::string& keyset_filename,
const std::string& message_filename,
const std::string& signature_filename,
const std::string& output_filename) {
auto keyset_handle = Util::ReadKeyset(keyset_filename);
auto primitive_result =
keyset_handle->GetPrimitive<crypto::tink::PublicKeyVerify>();
if (!primitive_result.ok()) {
std::clog << "Getting PublicKeyVerify-primitive from the factory "
<< "failed: " << primitive_result.status().error_message()
<< std::endl;
exit(1);
}
auto public_key_verify = std::move(primitive_result.ValueOrDie());
std::clog << "Verifying signature from file " << signature_filename
<< " of the message from file " << message_filename
<< " using public keyset from file " << keyset_filename
<< "..." << std::endl;
std::string signature = Util::Read(signature_filename);
std::string message = Util::Read(message_filename);
std::string result;
auto verify_status = public_key_verify->Verify(signature, message);
if (!verify_status.ok()) {
std::clog << "Error while verifying the signature: "
<< verify_status.error_message() << std::endl;
result = "invalid";
} else {
result = "valid";
}
std::clog << "Writing the result to file " << output_filename
<< "..." << std::endl;
Util::Write(result, output_filename);
}
int main(int argc, char** argv) {
if (argc == 1) {
PrintUsageInfo();
exit(1);
}
Util::InitTink();
std::string operation = argv[1];
if (operation == "gen-private-key") {
if (argc != 3) {
PrintUsageInfo();
exit(1);
}
std::string output_filename = argv[2];
GeneratePrivateKey(output_filename);
} else if (operation == "get-public-key") {
if (argc != 4) {
PrintUsageInfo();
exit(1);
}
std::string private_keyset_filename = argv[2];
std::string output_filename = argv[3];
ExtractPublicKey(private_keyset_filename, output_filename);
} else if (operation == "sign") {
if (argc != 5) {
PrintUsageInfo();
exit(1);
}
std::string keyset_filename = argv[2];
std::string message_filename = argv[3];
std::string output_filename = argv[4];
Sign(keyset_filename, message_filename, output_filename);
} else if (operation == "verify") {
if (argc != 6) {
PrintUsageInfo();
exit(1);
}
std::string keyset_filename = argv[2];
std::string message_filename = argv[3];
std::string signature_filename = argv[4];
std::string output_filename = argv[5];
Verify(keyset_filename, message_filename, signature_filename,
output_filename);
} else {
std::clog << "Unknown operation. Supported operations are: "
<< "gen-private-key get-public-key sign verify" << std::endl;
exit(1);
}
std::clog << "Done!" << std::endl;
return 0;
}