public void Sign( [Argument(Name = "KEY-ID", Description = "A private key to use for signing.")] Guid keyId, [Argument(Name = "VERSION", Description = "A version number to sign.")] int version, [Option( 'p', ValueName = "PASSPHRASE", Description = "Take passphrase through this option instead of prompt." )] string?passphrase = null, [Option( 'E', ValueName = "FILE", Description = "Bencodex file to use for extra data. " + "For standard input, use a hyphen (`-'). " + "For an actual file named a hyphen, prepend `./', i.e., `./-'." )] string?extraFile = null, [Option( 'e', ValueName = "KEY=VALUE", Description = "Set a value to a key on extra Bencodex dictionary. " + "Can be applied multiple times (e.g., `-e foo=1 -e bar=baz'). " + "This option implies the extra data to be a Bencodex dictionary, " + "hence cannot be used together with -E/--extra-file option." )] string[]?extra = null ) { PrivateKey key = new KeyCommand().UnprotectKey(keyId, passphrase); IValue? extraValue = null; if (extraFile is string path) { if (extra is string[] e && e.Length > 0) { throw Utils.Error( "-E/--extra-file and -e/--extra cannot be used together at a time." ); } var codec = new Codec(); if (path == "-") { // Stream for stdin does not support .Seek() using MemoryStream buffer = new MemoryStream(); using (Stream stream = Console.OpenStandardInput()) { stream.CopyTo(buffer); } buffer.Seek(0, SeekOrigin.Begin); extraValue = codec.Decode(buffer); } else { using Stream stream = File.Open(path, FileMode.Open, FileAccess.Read); extraValue = codec.Decode(stream); } } else if (extra is string[] e && e.Length > 0) { var dict = Bencodex.Types.Dictionary.Empty; foreach (string pair in e) { int sepPos = pair.IndexOf('='); if (sepPos < 0) { throw Utils.Error( "-e/--extra must be a pair of KEY=VALUE, but no equal (=) separator: " + $"`{pair}'." ); } string key_ = pair.Substring(0, sepPos); string value = pair.Substring(sepPos + 1); dict = dict.SetItem(key_, value); } extraValue = dict; } AppProtocolVersion v = AppProtocolVersion.Sign(key, version, extraValue); Console.WriteLine(v.Token); }
public void Verify( [Argument( Name = "APV-TOKEN", Description = "An app protocol version token to verify. " + "Read from the standard input if omitted." )] string?token = null, [Option( 'p', ValueName = "PUBLIC-KEY", Description = "Public key(s) to be used for verification. " + "Can be applied multiple times." )] string[]?publicKey = null, [Option( 'K', Description = "Do not use any keys in the key store, " + "but only -p/--public-key options." )] bool noKeyStore = false ) { AppProtocolVersion v = ParseAppProtocolVersionToken(token); if (publicKey is string[] pubKeyHexes) { foreach (string pubKeyHex in pubKeyHexes) { string opt = $"-p/--public-key=\"{pubKeyHex}\""; PublicKey pubKey; try { pubKey = new PublicKey(ByteUtil.ParseHex(pubKeyHex)); } catch (Exception e) { throw Utils.Error($"The {opt} is not a valid public key. {e.Message}"); } if (v.Verify(pubKey)) { Console.Error.WriteLine( "The signature successfully was verified using the {0}.", opt ); return; } Console.Error.WriteLine( "The signature was failed to verify using the {0}.", opt ); } } if (!noKeyStore) { KeyCommand keyInstance = new KeyCommand(); IEnumerable <Tuple <Guid, ProtectedPrivateKey> > ppks = keyInstance.KeyStore.List() .Where(pair => pair.Item2.Address.Equals(v.Signer)); foreach (Tuple <Guid, ProtectedPrivateKey> pair in ppks) { pair.Deconstruct(out Guid keyId, out ProtectedPrivateKey ppk); PublicKey pubKey = keyInstance.UnprotectKey(keyId).PublicKey; if (v.Verify(pubKey)) { Console.Error.WriteLine( "The signature successfully was verified using the key {0}.", keyId ); return; } Console.Error.WriteLine( "The signature was failed to verify using the key {0}.", keyId ); } } throw Utils.Error("Failed to verify."); }