When Facebook sends real-time updates, they include a X-Hub-Signature in the HTTP header. According to their documentation (http://developers.facebook.com/docs/api/realtime), they're using SHA1 and the application secret as the key. I tried to verify the signature like this:
public void MyAction() {
string signature = request.Headers["X-Hub-Signature"];
request.InputStream.Position = 0;
StreamReader reader = new StreamReader(request.InputStream);
string json = reader.ReadToEnd();
var hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(json), UTF8Encoding.UTF8.GetBytes("MySecret"));
var hmacBase64 = ToUrlBase64String(hmac);
bool isValid = signature.Split('=')[1] == hmacBase64;
}
private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) {
using (var hmacAlgorithm = new System.Security.Cryptography.HMACSHA1(keyBody)) {
hmacAlgorithm.ComputeHash(dataToSign);
return hmacAlgorithm.Hash;
}
}
private static string ToUrlBase64String(byte[] Input) {
return Convert.ToBase64String(Input).Replace("=", String.Empty)
.Replace('+', '-')
.Replace('/', '_');
}
But I can't seem to get this to ever validate. Any thoughts on what I'm doing wrong?
Thanks in advance.
In case someone will need this information:
What Kelvin offered might work, but it seems very cumbersome.
All you need is instead of using the ToUrlBase64String function just use the ConvertToHexadecimal function.
See fully updated code below:
public void MyAction() {
string signature = request.Headers["X-Hub-Signature"];
request.InputStream.Position = 0;
StreamReader reader = new StreamReader(request.InputStream);
string json = reader.ReadToEnd();
var hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(json), UTF8Encoding.UTF8.GetBytes("MySecret"));
var hmacHex = ConvertToHexadecimal(hmac);
bool isValid = signature.Split('=')[1] == hmacHex ;
}
private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) {
using (var hmacAlgorithm = new System.Security.Cryptography.HMACSHA1(keyBody)) {
return hmacAlgorithm.ComputeHash(dataToSign);
}
}
private static string ConvertToHexadecimal(IEnumerable<byte> bytes)
{
var builder = new StringBuilder();
foreach (var b in bytes)
{
builder.Append(b.ToString("x2"));
}
return builder.ToString();
}
The code below will resolve the problem for you:
public String hmacSha1(String keyString, byte[] in) throws GeneralSecurityException {
Mac hmac = Mac.getInstance("HmacSHA1");
int keySize = keyString.length();
byte[] keyBytes = new byte[keySize];
for (int i = 0; i < keyString.length(); i++) {
keyBytes[i] = (byte) keyString.charAt(i);
}
Key key = new SecretKeySpec(keyBytes, "HmacSHA1");
hmac.init(key);
hmac.update(in);
byte[] bb = hmac.doFinal();
StringBuilder v = new StringBuilder();
for (int i = 0; i < bb.length; i++) {
int ch = bb[i];
int d1 = (ch >> 4) & 0xf;
int d2 = (ch) & 0xf;
if (d1 < 10) {
v.append((char) ('0' + d1));
} else {
v.append((char) ('a' + d1 - 10));
}
if (d2 < 10) {
v.append((char) ('0' + d2));
} else {
v.append((char) ('a' + d2 - 10));
}
}
return v.toString();
}
public String callback(HttpServletRequest request) throws IOException {
InputStream in = request.getInputStream();
StringBuilder builder = new StringBuilder();
byte[] buffer = new byte[1024];
while (in.read(buffer) > 0) {
builder.append(new String(buffer));
}
String signature = request.getHeader("X-Hub-Signature");
try {
String signed = subscriptionService.hmacSha1("YOUR_SECRET", builder.toString().getBytes());
if (signature.startsWith("sha1=") && signature.substring(4).equals(signed)) {
// process the update
....
}
} catch (GeneralSecurityException ex) {
log.warn(ex.getMessage());
}
return null;
}
Related
I have a program that needs to scan for other devices running my program on the network. The solution I came up with was to call each ipAddress to see if my program is running.
The code below is completely blocking the cpu:-
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FileWire
{
class SearchNearby
{
private bool pc_search_cancelled = false;
private SynchronizedCollection<Thread> PCSearchThreadList;
private ConcurrentDictionary<String, String> NearbyPCList;
public void NewPcFound(string s, string s1)
{
Console.WriteLine(string.Format("PC Found at: {0} PC Name: {1}", s, s1));
}
public SearchNearby()
{
startPCScan();
while (true)
{
bool isAnyAlive = false;
foreach(Thread t in PCSearchThreadList)
{
isAnyAlive |= t.IsAlive;
}
if (!isAnyAlive)
{
Console.WriteLine("Search Complete");
foreach (var a in NearbyPCList)
{
Console.WriteLine(a.Key + " ;; " + a.Value);
}
startPCScan();
}
Thread.Sleep(100);
}
}
private void startPCScan()
{
PCSearchThreadList = new SynchronizedCollection<Thread>();
NearbyPCList = new ConcurrentDictionary<String, String>();
pc_search_cancelled = false;
String add = "";
System.Net.IPAddress[] ad = System.Net.Dns.GetHostByName(System.Net.Dns.GetHostName()).AddressList;
foreach (System.Net.IPAddress ip in ad)
{
add += ip.ToString() + "\n";
}
bool connected;
if (add.Trim(' ').Length == 0)
{
connected = false;
}
else
{
connected = true;
}
if (connected)
{
try
{
String[] addresses = add.Split('\n');
foreach (String address in addresses)
{
int myIP = int.Parse(address.Substring(address.LastIndexOf(".") + 1));
for (int def = 0; def <= 10; def++)
{
int finalDef = def;
for (int j = 0; j < 10; j++)
{
string finalJ = j.ToString();
Thread thread = new Thread(new ThreadStart(() =>
{
if (!pc_search_cancelled)
{
for (int i = (finalDef * 25); i < (finalDef * 25) + 25 && i <= 255; i++)
{
if (!pc_search_cancelled)
{
if (i != myIP)
{
String callToAddress = "http://" + address.Substring(0, address.LastIndexOf(".")) + "." + i + ":" + (1234 + int.Parse(finalJ)).ToString();
String name = canGetNameAndAvatar(callToAddress);
if (name != null)
{
NearbyPCList[callToAddress] = name;
NewPcFound(callToAddress, name);
}
}
}
}
}
}));
PCSearchThreadList.Add(thread);
thread.Start();
}
}
}
} catch (Exception e) {
}
}
}
private String canGetNameAndAvatar(String connection)
{
String link = connection + "/getAvatarAndName";
link = link.Replace(" ", "%20");
try
{
var client = new HttpClient();
client.Timeout = TimeSpan.FromMilliseconds(500);
var a = new Task<HttpResponseMessage>[1];
a[0] = client.GetAsync(link);
Task.WaitAll(a);
var b = a[0].Result.Content.ReadAsStringAsync();
Task.WaitAll(b);
Console.WriteLine(b.Result);
string result = b.Result;
result = result.Substring(result.IndexOf("<body>") + 6, result.IndexOf("</body>") - (result.IndexOf("<body>") + 6));
AvtarAndName json = JsonConvert.DeserializeObject<AvtarAndName>(result);
if (json != null)
{
return json.name;
}
}
catch
{
return null;
}
return null;
}
}
}
This is the exact C# version of the java code I was using in Java:-
import com.sun.istack.internal.Nullable;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class PCScan {
private static boolean pc_search_cancelled = false;
private static List<Thread> PCSearchThreadList;
private static HashMapWithListener<String, String> NearbyPCList;
public static void main(String[] args) {
start();
while (true) {
int numCompleted = 0;
for (Thread t : PCSearchThreadList) {
if (!t.isAlive()) {
numCompleted++;
}
}
if (numCompleted == PCSearchThreadList.size()) {
start();
}
}
}
private static void start() {
try {
startPCScan();
} catch (SocketException e) {
e.printStackTrace();
}
NearbyPCList.setPutListener(new HashMapWithListener.putListener() {
#Override
public void onPut(Object key, Object value) {
System.out.println(key.toString() + ";;" + value.toString());
}
});
}
private static void startPCScan() throws SocketException {
pc_search_cancelled = false;
PCSearchThreadList = new CopyOnWriteArrayList<>();
NearbyPCList = new HashMapWithListener<>();
Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces();
boolean connected;
String add = "";
while (enumeration.hasMoreElements()) {
NetworkInterface interfacea = enumeration.nextElement();
if (!interfacea.isLoopback()) {
Enumeration<InetAddress> enumeration1 = interfacea.getInetAddresses();
while (enumeration1.hasMoreElements()) {
String address = enumeration1.nextElement().getHostAddress();
if (address.split("\\.").length == 4) {
add += address + "\n";
}
}
}
}
System.out.println(add);
connected = true;
if (connected) {
try {
String[] addresses = add.split("\n");
addresses = new HashSet<String>(Arrays.asList(addresses)).toArray(new String[0]);
for (String address : addresses) {
int myIP = Integer.parseInt(address.substring(address.lastIndexOf(".") + 1));
for (int def = 0; def <= 10; def++) {
int finalDef = def;
for (int j = 0; j < 10; j++) {
int finalJ = j;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
if (!pc_search_cancelled) {
for (int i = (finalDef * 25); i < (finalDef * 25) + 25 && i <= 255; i++) {
if (!pc_search_cancelled) {
if (i != myIP) {
String callToAddress = "http://" + address.substring(0, address.lastIndexOf(".")) + "." + i + ":" + String.valueOf(Integer.parseInt("1234") + finalJ);
String name = canGetNameAndAvatar(callToAddress);
if (name != null) {
NearbyPCList.put(callToAddress, name);
}
}
}
}
}
}
});
PCSearchThreadList.add(thread);
thread.start();
}
}
// }
// }).start();
}
} catch (Exception e) {
}
}
}
private static String canGetNameAndAvatar(String connection) {
String link = connection + "/getAvatarAndName";
link = link.replaceAll(" ", "%20");
try {
HttpClient client = new DefaultHttpClient();
HttpParams httpParams = client.getParams();
httpParams.setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, 500);
HttpGet request = new HttpGet();
request.setURI(new URI(link));
HttpResponse response = client.execute(request);
BufferedReader in = new BufferedReader(new
InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line="";
while ((line = in.readLine()) != null) {
sb.append(line);
break;
}
in.close();
String result = sb.toString();
result = result.substring(result.indexOf("<body>") + 6, result.indexOf("</body>"));
JSONObject json = new JSONObject(result);
if (json != null) {
return json.getString("name");
}
}
catch (Exception ignored){
return null;
}
return null;
}
static class HashMapWithListener<K, V> extends HashMap<K, V> {
private putListener PutListener;
public void setPutListener(putListener PutListener) {
this.PutListener = PutListener;
}
#Nullable
#Override
public V put(K key, V value) {
PutListener.onPut(key, value);
return super.put(key, value);
}
interface putListener {
public void onPut(Object key, Object value);
}
}
}
The java code runs absolutely fine and only uses about 20 percent cpu while c# code absolutely locks the PC. I tried Webclient, webrequest, httpClient. All have literally the same performance.
I need the code to be in c# as I can't include whole JRE in my program since it is too large. The rest of my program and GUI is in WPF format.
Also, I need the code to take a maximum of 50seconds while scanning ports 1234-1243. This code also works absolutely fine even on a midrange android phone. So, I don't know what the problem is.
I would suggest something like this (I've simplified it for the sake of an example):
private static HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromMilliseconds(500) };
private async Task<Something> GetSomething(string url)
{
using (HttpResponseMessage response = await _client.GetAsync(url))
{
string json = await response.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Something>(json);
}
}
private async Task<Something[]> GetSomethings(string[] urls)
{
IEnumerable<Task<Something>> requestTasks = urls.Select(u => GetSomething(u));
Something[] results = await Task.WhenAll<Something>(requestTasks);
return results;
}
You should also make the method calling GetSomethings async, and await it, and do the same all the way up the call chain.
async/await uses a thread pool to execute, and the thread is actually suspended while the IO part of the request occurs, meaning that no CPU time is used during this period. When then IO part is done, it resumes the code at the await.
Related information:
Asynchronous programming documentation
How and when to use 'async' and 'await'
You are using threads and multithreading completely wrong.
Because I cannot really understand what you are trying to do because everything is cramped into one function, I cannot provide you with a more detailed solution.
But let me suggest the following: I understand, you want to execute some operation in the background connecting to some other computer, try something like this
var taskList = new List<Task>();
foreach (var pc in computers)
{
var currentPcTask = Task.Run(() => DoYourWorkForSomePcHere(pc));
taskList.Add(currentPcTask);
}
Task.WaitAll(taskList.ToArray());
This will be very CPU efficient.
i have a method that i need to remake in C# based on this python code.
def _generateHash(self, password, time_stamp, nonce):
import hashlib
shaPw = hashlib.sha1()
shaPw.update( password )
m = hashlib.sha1()
m.update(str(time_stamp))
m.update(nonce)
m.update(shaPw.hexdigest())
m.update(self.api_key_secret)
return m.hexdigest()
hashing in C# is allot different compared to python. also my hashing experience is not that great. is there anybody that can help me?
this is wat i have right now.
private string GenerateHash(string password, double timeStamp, string nonce)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var pwHash = sha1.ComputeHash(Encoding.UTF8.GetBytes(password));
using (SHA1Managed sha1total = new SHA1Managed())
{
sha1total.ComputeHash(Encoding.UTF8.GetBytes(timeStamp.ToString()));
sha1total.ComputeHash(Encoding.UTF8.GetBytes(nonce));
string hexaHashPW = "";
foreach (byte b in pwHash)
{
hexaHashPW += String.Format("{0:x2}", b);
}
sha1total.ComputeHash(Encoding.UTF8.GetBytes(hexaHashPW));
sha1total.ComputeHash(Encoding.UTF8.GetBytes(_SecretApiKey));
var hmac = new HMACSHA1();
//string hexaHashTotal = "";
//foreach (byte b in sha1total.Hash)
//{
// hexaHashTotal += String.Format("{0:x2}", b);
//}
hmac.ComputeHash(sha1total.Hash);
var hexaHashTotal = hmac.Hash;
var endhash = BitConverter.ToString(hexaHashTotal).Replace("-", "");
return endhash;
}
}
}
after even more research and trail and error i found the way to produce the same hash as the python code.
this is the answer for others that have problems with this.
private string GenerateHash(string password, double timeStamp, string nonce)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var pwHash = sha1.ComputeHash(Encoding.UTF8.GetBytes(password));
using (SHA1Managed sha1total = new SHA1Managed())
{
string hexaHashPW = "";
foreach (byte b in pwHash)
{
hexaHashPW += String.Format("{0:x2}", b);
}
var hmacPW = new HMACSHA1();
hmacPW.ComputeHash(pwHash);
sha1total.ComputeHash(Encoding.UTF8.GetBytes(timeStamp.ToString() + nonce + hexaHashPW + _SecretApiKey));
var hmac = new HMACSHA1();
string hexaHashTotal = "";
foreach (byte b in sha1total.Hash)
{
hexaHashTotal += String.Format("{0:x2}", b);
}
hmac.ComputeHash(sha1total.Hash);
return hexaHashTotal.ToLower();
}
}
}
I read this article , I want to get sent bytes and receive bytes for all process, but sent bytes and receive bytes of all process always return 0;
Here is my code:
namespace Network
{
public class NetworkTraffic
{
private List<PerformanceCounter> listBytesSentPerformanceCounter;
private List<PerformanceCounter> listBytesReceivedPerformanceCounter;
//private PerformanceCounter bytesSentPerformanceCounter;
//private PerformanceCounter bytesReceivedPerformanceCounter;
public NetworkTraffic()
{
listBytesSentPerformanceCounter = new List<PerformanceCounter>();
listBytesReceivedPerformanceCounter = new List<PerformanceCounter>();
List<string> listInstanceName = GetInstanceName();
foreach (string str in listInstanceName)
{
PerformanceCounter bytesSentPerformanceCounter = new PerformanceCounter();
PerformanceCounter bytesReceivedPerformanceCounter = new PerformanceCounter();
bytesSentPerformanceCounter.CategoryName = ".NET CLR Networking 4.0.0.0";
bytesSentPerformanceCounter.CounterName = "Bytes Sent";
bytesSentPerformanceCounter.InstanceName = str;
bytesSentPerformanceCounter.ReadOnly = false;
listBytesSentPerformanceCounter.Add(bytesSentPerformanceCounter);
bytesReceivedPerformanceCounter.CategoryName = ".NET CLR Networking 4.0.0.0";
bytesReceivedPerformanceCounter.CounterName = "Bytes Received";
bytesReceivedPerformanceCounter.InstanceName = str;
bytesReceivedPerformanceCounter.ReadOnly = false;
listBytesReceivedPerformanceCounter.Add(bytesReceivedPerformanceCounter);
}
}
//public float GetBytesSent()
//{
// float bytesSent = bytesSentPerformanceCounter.RawValue;
// return bytesSent;
//}
//public float GetBytesReceived()
//{
// float bytesReceived = bytesReceivedPerformanceCounter.RawValue;
// return bytesReceived;
//}
private static List<string> GetInstanceName()
{
// Used Reflector to find the correct formatting:
string assemblyName = GetAssemblyName();
if ((assemblyName == null) || (assemblyName.Length == 0))
{
assemblyName = AppDomain.CurrentDomain.FriendlyName;
}
StringBuilder builder = new StringBuilder(assemblyName);
for (int i = 0; i < builder.Length; i++)
{
switch (builder[i])
{
case '/':
case '\\':
case '#':
builder[i] = '_';
break;
case '(':
builder[i] = '[';
break;
case ')':
builder[i] = ']';
break;
}
}
List<string> listInstanceName = new List<string>();
Process[] listProcess = Process.GetProcesses();
string InstanceName;
foreach (Process pro in listProcess)
{
InstanceName = string.Format(CultureInfo.CurrentCulture,
"{0}[{1}]",
builder.ToString(),
pro.Id);
listInstanceName.Add(InstanceName);
}
return listInstanceName;
}
private static string GetAssemblyName()
{
string str = null;
Assembly entryAssembly = Assembly.GetEntryAssembly();
if (entryAssembly != null)
{
AssemblyName name = entryAssembly.GetName();
if (name != null)
{
str = name.Name;
}
}
return str;
}
public static void Main()
{
NetworkTraffic networkTraffic = new NetworkTraffic();
try
{
while (true)
{
WebRequest webRequest = WebRequest.Create("http://www.google.com");
webRequest.Method = "GET";
using (WebResponse response = webRequest.GetResponse())
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
{
}
//Console.WriteLine("Bytes sent: {0}", networkTraffic.GetBytesSent());
//Console.WriteLine("Bytes received: {0}", networkTraffic.GetBytesReceived());
foreach (PerformanceCounter send in networkTraffic.listBytesSentPerformanceCounter)
{
Console.WriteLine("Instance name: " + send.InstanceName + " Sent: " + send.RawValue);
}
Thread.Sleep(1000);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadLine();
}
}
}
Anyone can help me resolve this.
in c#
public static string HashToString(string message, byte[] key)
{
byte[] b=new HMACSHA512(key).ComputeHash(Encoding.UTF8.GetBytes(message));
return Convert.ToBase64String(b);
}
client.DefaultRequestHeaders.Add("X-Hash", hash);
var encryptedContent = DataMotion.Security.Encrypt(key, Convert.FromBase64String(iv), serializedModel);
var request = client.PostAsync(ApiUrlTextBox.Text,encryptedContent,new JsonMediaTypeFormatter());
in java:
protected String hashToString(String serializedModel, byte[] key) {
String result = null;
Mac sha512_HMAC;
try {
sha512_HMAC = Mac.getInstance("HmacSHA512");
SecretKeySpec secretkey = new SecretKeySpec(key, "HmacSHA512");
sha512_HMAC.init(secretkey);
byte[] mac_data = sha512_HMAC.doFinal(serializedModel.getBytes("UTF-8"));
result = Base64.encodeBase64String(mac_data);
}catch(Exception e){
}
}
o/p: ye+AZPqaKrU14pui4U5gBCiAbegNvLVjzVdGK3rwG9QVzqKfIgyWBDTncORkNND3DA8jPba5xmC7B5OUwZEKlQ==
i have written hashtostring method in java based on c# code. is this currect? (output is different because every time process is dynamic in both cases.)
With different C# encoding
public static string SHA512_ComputeHash(string text, string secretKey)
{
var hash = new StringBuilder(); ;
byte[] secretkeyBytes = Encoding.UTF8.GetBytes(secretKey);
byte[] inputBytes = Encoding.UTF8.GetBytes(text);
using (var hmac = new HMACSHA512(secretkeyBytes))
{
byte[] hashValue = hmac.ComputeHash(inputBytes);
foreach (var theByte in hashValue)
{
hash.Append(theByte.ToString("x2"));
}
}
return hash.ToString();
}
Both java and C# code are giving same result(same hash code). You should check again.
Replace following line in java code at end
result = Base64.getEncoder().encodeToString(mac_data);
In c#
public static string HMACSHA512(this string Key, string TextToHash)
{
string HmacHashed = "";
if (string.IsNullOrEmpty(Key))
throw new ArgumentNullException("HMACSHA512: Key", "Parameter cannot be empty.");
if (string.IsNullOrEmpty(TextToHash))
throw new ArgumentNullException("HMACSHA512: TextToHash", "Parameter cannot be empty.");
if (Key.Length % 2 != 0 || Key.Trim().Length < 2)
{
throw new ArgumentNullException("HMACSHA512: Key", "Parameter cannot be odd or less than 2 characters.");
}
try
{
using (var HMACSHA512 = new HMACSHA512(Encoding.ASCII.GetBytes(Key)))
{
HmacHashed = BitConverter.ToString(HMACSHA512.ComputeHash(Encoding.ASCII.GetBytes(TextToHash))).Replace("-", string.Empty);
}
return HmacHashed;
}
catch (Exception ex)
{
throw new Exception("HMACSHA512: " + ex.Message);
}
}
Does anyone have an example of how I can sign a txt file, using a PGP key in C# and Bouncy Castle library. Not to encrypt the file, only to add a signature.
public void SignFile(String fileName,
Stream privateKeyStream,
String privateKeyPassword,
Stream outStream)
{
PgpSecretKey pgpSec = ReadSigningSecretKey(privateKeyStream);
PgpPrivateKey pgpPrivKey = null;
pgpPrivKey = pgpSec.ExtractPrivateKey(privateKeyPassword.ToCharArray());
PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, KeyStore.ParseHashAlgorithm(this.hash.ToString()));
sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
foreach (string userId in pgpSec.PublicKey.GetUserIds()) {
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
spGen.SetSignerUserId(false, userId);
sGen.SetHashedSubpackets(spGen.Generate());
}
CompressionAlgorithmTag compression = PreferredCompression(pgpSec.PublicKey);
PgpCompressedDataGenerator cGen = new PgpCompressedDataGenerator(compression);
BcpgOutputStream bOut = new BcpgOutputStream(cGen.Open(outStream));
sGen.GenerateOnePassVersion(false).Encode(bOut);
FileInfo file = new FileInfo(fileName);
FileStream fIn = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
Stream lOut = lGen.Open(bOut, PgpLiteralData.Binary, file);
int ch = 0;
while ((ch = fIn.ReadByte()) >= 0) {
lOut.WriteByte((byte)ch);
sGen.Update((byte) ch);
}
fIn.Close();
sGen.Generate().Encode(bOut);
lGen.Close();
cGen.Close();
outStream.Close();
}
public PgpSecretKey ReadSigningSecretKey(Stream inStream)
// throws IOException, PGPException, WrongPrivateKeyException
{
PgpSecretKeyRingBundle pgpSec = CreatePgpSecretKeyRingBundle(inStream);
PgpSecretKey key = null;
IEnumerator rIt = pgpSec.GetKeyRings().GetEnumerator();
while (key == null && rIt.MoveNext())
{
PgpSecretKeyRing kRing = (PgpSecretKeyRing)rIt.Current;
IEnumerator kIt = kRing.GetSecretKeys().GetEnumerator();
while (key == null && kIt.MoveNext())
{
PgpSecretKey k = (PgpSecretKey)kIt.Current;
if(k.IsSigningKey)
key = k;
}
}
if(key == null)
throw new WrongPrivateKeyException("Can't find signing key in key ring.");
else
return key;
}
DidiSoft's code in a working fashion:
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
namespace BouncyCastleTest.PGP
{
// http://www.programcreek.com/java-api-examples/index.php?api=org.bouncycastle.bcpg.HashAlgorithmTags
// http://stackoverflow.com/questions/6337985/how-to-sign-a-txt-file-with-a-pgp-key-in-c-sharp-using-bouncy-castle-library
class SignOnly
{
public void SignFile(string hashAlgorithm, string fileName, System.IO.Stream privateKeyStream
, string privateKeyPassword, System.IO.Stream outStream)
{
PgpSecretKey pgpSec = ReadSigningSecretKey(privateKeyStream);
PgpPrivateKey pgpPrivKey = null;
pgpPrivKey = pgpSec.ExtractPrivateKey(privateKeyPassword.ToCharArray());
PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, ParseHashAlgorithm(hashAlgorithm));
sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
foreach (string userId in pgpSec.PublicKey.GetUserIds())
{
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
spGen.SetSignerUserId(false, userId);
sGen.SetHashedSubpackets(spGen.Generate());
}
CompressionAlgorithmTag compression = PreferredCompression(pgpSec.PublicKey);
PgpCompressedDataGenerator cGen = new PgpCompressedDataGenerator(compression);
BcpgOutputStream bOut = new BcpgOutputStream(cGen.Open(outStream));
sGen.GenerateOnePassVersion(false).Encode(bOut);
System.IO.FileInfo file = new System.IO.FileInfo(fileName);
System.IO.FileStream fIn = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
System.IO.Stream lOut = lGen.Open(bOut, PgpLiteralData.Binary, file);
int ch = 0;
while ((ch = fIn.ReadByte()) >= 0)
{
lOut.WriteByte((byte)ch);
sGen.Update((byte)ch);
}
fIn.Close();
sGen.Generate().Encode(bOut);
lGen.Close();
cGen.Close();
outStream.Close();
}
public static PgpSecretKeyRingBundle CreatePgpSecretKeyRingBundle(System.IO.Stream keyInStream)
{
return new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(keyInStream));
}
public PgpSecretKey ReadSigningSecretKey(System.IO.Stream keyInStream)
{
PgpSecretKeyRingBundle pgpSec = CreatePgpSecretKeyRingBundle(keyInStream);
PgpSecretKey key = null;
System.Collections.IEnumerator rIt = pgpSec.GetKeyRings().GetEnumerator();
while (key == null && rIt.MoveNext())
{
PgpSecretKeyRing kRing = (PgpSecretKeyRing)rIt.Current;
System.Collections.IEnumerator kIt = kRing.GetSecretKeys().GetEnumerator();
while (key == null && kIt.MoveNext())
{
PgpSecretKey k = (PgpSecretKey)kIt.Current;
if (k.IsSigningKey)
key = k;
}
}
if (key == null)
throw new System.Exception("Wrong private key - Can't find signing key in key ring.");
else
return key;
}
public static string GetDigestName(int hashAlgorithm)
{
switch ((Org.BouncyCastle.Bcpg.HashAlgorithmTag)hashAlgorithm)
{
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha1:
return "SHA1";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.MD2:
return "MD2";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.MD5:
return "MD5";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.RipeMD160:
return "RIPEMD160";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha256:
return "SHA256";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha384:
return "SHA384";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha512:
return "SHA512";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha224:
return "SHA224";
case Org.BouncyCastle.Bcpg.HashAlgorithmTag.Tiger192:
return "TIGER";
default:
throw new Org.BouncyCastle.Bcpg.OpenPgp.PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
}
}
public static Org.BouncyCastle.Bcpg.HashAlgorithmTag ParseHashAlgorithm(string hashAlgorithm)
{
switch (hashAlgorithm.ToUpper())
{
case "SHA1":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha1;
case "MD2":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.MD2;
case "MD5":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.MD5;
case "RIPEMD160":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.RipeMD160;
case "SHA256":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha256;
case "SHA384":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha384;
case "SHA512":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha512;
case "SHA224":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha224;
case "TIGER":
return Org.BouncyCastle.Bcpg.HashAlgorithmTag.Tiger192;
default:
throw new Org.BouncyCastle.Bcpg.OpenPgp.PgpException("unknown hash algorithm name in ParseHashAlgorithm: " + hashAlgorithm);
}
}
public static CompressionAlgorithmTag PreferredCompression(PgpPublicKey publicKey)
{
return CompressionAlgorithmTag.BZip2;
}
}
}
There is also an example in the BouncyCastle source-code (including how to verify):
using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Bcpg.OpenPgp;
namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
{
/**
* A simple utility class that signs and verifies files.
* <p>
* To sign a file: SignedFileProcessor -s [-a] fileName secretKey passPhrase.<br/>
* If -a is specified the output file will be "ascii-armored".</p>
* <p>
* To decrypt: SignedFileProcessor -v fileName publicKeyFile.</p>
* <p>
* <b>Note</b>: this example will silently overwrite files, nor does it pay any attention to
* the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
* will have been used.</p>
* <p>
* <b>Note</b>: the example also makes use of PGP compression. If you are having difficulty Getting it
* to interoperate with other PGP programs try removing the use of compression first.</p>
*/
public sealed class SignedFileProcessor
{
private SignedFileProcessor() {}
/**
* verify the passed in file as being correctly signed.
*/
private static void VerifyFile(
Stream inputStream,
Stream keyIn)
{
inputStream = PgpUtilities.GetDecoderStream(inputStream);
PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
PgpCompressedData c1 = (PgpCompressedData) pgpFact.NextPgpObject();
pgpFact = new PgpObjectFactory(c1.GetDataStream());
PgpOnePassSignatureList p1 = (PgpOnePassSignatureList) pgpFact.NextPgpObject();
PgpOnePassSignature ops = p1[0];
PgpLiteralData p2 = (PgpLiteralData) pgpFact.NextPgpObject();
Stream dIn = p2.GetInputStream();
PgpPublicKeyRingBundle pgpRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn));
PgpPublicKey key = pgpRing.GetPublicKey(ops.KeyId);
Stream fos = File.Create(p2.FileName);
ops.InitVerify(key);
int ch;
while ((ch = dIn.ReadByte()) >= 0)
{
ops.Update((byte)ch);
fos.WriteByte((byte) ch);
}
fos.Close();
PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
PgpSignature firstSig = p3[0];
if (ops.Verify(firstSig))
{
Console.Out.WriteLine("signature verified.");
}
else
{
Console.Out.WriteLine("signature verification failed.");
}
}
/**
* Generate an encapsulated signed file.
*
* #param fileName
* #param keyIn
* #param outputStream
* #param pass
* #param armor
*/
private static void SignFile(
string fileName,
Stream keyIn,
Stream outputStream,
char[] pass,
bool armor,
bool compress)
{
if (armor)
{
outputStream = new ArmoredOutputStream(outputStream);
}
PgpSecretKey pgpSec = PgpExampleUtilities.ReadSecretKey(keyIn);
PgpPrivateKey pgpPrivKey = pgpSec.ExtractPrivateKey(pass);
PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
foreach (string userId in pgpSec.PublicKey.GetUserIds())
{
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
spGen.SetSignerUserId(false, userId);
sGen.SetHashedSubpackets(spGen.Generate());
// Just the first one!
break;
}
Stream cOut = outputStream;
PgpCompressedDataGenerator cGen = null;
if (compress)
{
cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.ZLib);
cOut = cGen.Open(cOut);
}
BcpgOutputStream bOut = new BcpgOutputStream(cOut);
sGen.GenerateOnePassVersion(false).Encode(bOut);
FileInfo file = new FileInfo(fileName);
PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
Stream lOut = lGen.Open(bOut, PgpLiteralData.Binary, file);
FileStream fIn = file.OpenRead();
int ch = 0;
while ((ch = fIn.ReadByte()) >= 0)
{
lOut.WriteByte((byte) ch);
sGen.Update((byte)ch);
}
fIn.Close();
lGen.Close();
sGen.Generate().Encode(bOut);
if (cGen != null)
{
cGen.Close();
}
if (armor)
{
outputStream.Close();
}
}
public static void Main(
string[] args)
{
// TODO provide command-line option to determine whether to use compression in SignFile
if (args[0].Equals("-s"))
{
Stream keyIn, fos;
if (args[1].Equals("-a"))
{
keyIn = File.OpenRead(args[3]);
fos = File.Create(args[2] + ".asc");
SignFile(args[2], keyIn, fos, args[4].ToCharArray(), true, true);
}
else
{
keyIn = File.OpenRead(args[2]);
fos = File.Create(args[1] + ".bpg");
SignFile(args[1], keyIn, fos, args[3].ToCharArray(), false, true);
}
keyIn.Close();
fos.Close();
}
else if (args[0].Equals("-v"))
{
using (Stream fis = File.OpenRead(args[1]),
keyIn = File.OpenRead(args[2]))
{
VerifyFile(fis, keyIn);
}
}
else
{
Console.Error.WriteLine("usage: SignedFileProcessor -v|-s [-a] file keyfile [passPhrase]");
}
}
}
}