Snippets

LIQUID Barcodes SHOP API - Payment provider offer token decryption

Created by Magnus Olstad Hansen last modified Dzmitry Zubialevich
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Utilities.IO;

void Main()
{
    /*
     * Decryption demonstration
    */
	
	var modelJson = PgpDecrypt(/* incoming offer token */, /* your private PGP key */, /* your secret PGP phrase */);
	var model = ServiceStack.Text.JsonSerializer.DeserializeFromString<OfferToken>(modelJson);
    
    // proceed with payment for model...
}

string PgpDecrypt(string base64Str, string privateKey, string password)
{
	var encryptedBytes = Convert.FromBase64String(base64Str);
	var str = Encoding.UTF8.GetString(encryptedBytes);
	var decoded = new MemoryStream();

	using (var stream = new MemoryStream())
	using (var writer = new StreamWriter(stream))
	{
		writer.Write(str);
		writer.Flush();
		stream.Seek(0, SeekOrigin.Begin);
		var input = PgpUtilities.GetDecoderStream(stream);

		try
		{
			var pgpObjF = new PgpObjectFactory(input);
			PgpEncryptedDataList enc;
			var obj = pgpObjF.NextPgpObject();
			if (obj is PgpEncryptedDataList)
			{
				enc = (PgpEncryptedDataList) obj;
			}
			else
			{
				enc = (PgpEncryptedDataList) pgpObjF.NextPgpObject();
			}

			var pbe = enc
				.GetEncryptedDataObjects()
				.Cast<PgpPublicKeyEncryptedData>()
				.FirstOrDefault();

			if (pbe == null)
			{
				return string.Empty;
			}

			var privKey = ReadPrivateKey(privateKey, password, pbe.KeyId);

			if (privKey == null)
			{
				return string.Empty;
			}

			var clear = pbe.GetDataStream(privKey);

			var plainFact = new PgpObjectFactory(clear);
			var message = plainFact.NextPgpObject();

			if (message is PgpCompressedData)
			{
				var cData = (PgpCompressedData)message;
				var pgpFact = new PgpObjectFactory(cData.GetDataStream());
				message = pgpFact.NextPgpObject();

				var literalData = (PgpLiteralData)message;
				var unc = literalData.GetInputStream();
				Streams.PipeAll(unc, decoded);

				unc.Flush();
			}


			if (pbe.IsIntegrityProtected())
			{
				if (!pbe.Verify())
				{
					throw new Exception("Message failed integrity check.");
				}
			}

			decoded.Position = 0;
			var result = StreamToString(decoded);

			decoded.Flush();
			input.Flush();
			clear.Flush();
			return result;
		}
		catch (Exception e)
		{
			throw new Exception(e.Message);
		}
	}
}

string StreamToString(Stream stream)
{
	using (var reader = new StreamReader(stream, Encoding.UTF8))
	{
		return reader.ReadToEnd();
	}
}

PgpPrivateKey ReadPrivateKey(string privateKeyStr, string passPhrase, long keyId)
{
	var secreKey = ReadSecretKey(privateKeyStr, keyId);
	var privateKey = secreKey.ExtractPrivateKey(passPhrase.ToCharArray());
	if (privateKey != null)
	{
		return privateKey;
	}
	throw new ArgumentException("No private key found in secret key.");
}

PgpSecretKey ReadSecretKey(string privateKey, long keyId)
{
	using (var stream = new MemoryStream())
	using (var writer = new StreamWriter(stream))
	{
		writer.Write(privateKey);
		writer.Flush();
		stream.Position = 0;

		using (var inputStream = PgpUtilities.GetDecoderStream(stream))
		{
			var secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream);
			var foundKey = secretKeyRingBundle.GetSecretKey(keyId);
			if (foundKey != null)
				return foundKey;
		}
	}
	throw new ArgumentException("Can't find signing key in key ring.");
}

class OfferToken
{
	public DateTimeOffset Expiration { get; set; }
	public Item Item { get; set; }
	public string InternalOfferToken { get; set; }
}

class Item
{
	public long ShopOfferId { get; set; }
	public decimal RetailPrice { get; set; }
	public string Currency { get; set; }
	public string Type { get; set; }
	public string Description { get; set; }
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.