ECDSA sign with BouncyCastle and verify with Crypto++ - java

Here is the Java code:
public static String sign(String data) throws Exception {
KeyPair keyPair = loadKeyPair(System.getProperty("user.dir"), "ECDSA");
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initSign(keyPair.getPrivate(), new SecureRandom());
byte[] message = data.getBytes();
signature.update(message);
byte[] sigBytes = signature.sign();
String signatureStr = new BigInteger(1, sigBytes).toString(16);
return signatureStr;
}
Then the C++ Code to verify signatures
bool VerifyMessage( const ECDSA<ECP, SHA256>::PublicKey& key, const string& message, const string& signature )
{
bool result = false;
// Hexa encoding version, more readable
std::string decodedSignature;
StringSource(signature, true,
new HexDecoder(
new StringSink(decodedSignature)));
StringSource(decodedSignature+message, true,
new SignatureVerificationFilter(ECDSA<ECP,SHA256>::Verifier(key),
new ArraySink((byte*)&result, sizeof(result))));
return result;
}
I was thinking that I need to encode my signature to hexa but it didn't resolve my problem. I've written a c++ version of the sign method using crypto++ and it's verified. so why when I use the java code, the signature is not verified. Thanks

... why when I use the java code, the signature is not verified?
OpenSSL and Java use an ASN.1/DER encoding for the signature, and Crypto++ uses IEEE P1363's format for the signature.
ASN.1: SEQUENCE ::= { r INTEGER, s INTEGER }
P1363: [byte array r][byte array s]
You need to convert between the formats. Crypto++ provides DSAConvertSignatureFormat to convert between formats. There is an example on the Crypto++ wiki at Elliptic Curve Digital Signature Algorithm | OpenSSL and Java Interop.
Here is the Crypto++ code from the wiki. It uses OpenSSL and its command line tools rather than Java. There is no material difference because OpenSSL and Java output signatures in ASN.1/DER format.
#include "cryptlib.h"
#include "eccrypto.h"
#include "files.h"
#include "dsa.h"
#include "sha.h"
#include "hex.h"
#include <iostream>
using namespace CryptoPP;
int main(int argc, char* argv[])
{
// Load DER encoded public key
FileSource pubKey("secp256k1-pub.der", true /*binary*/);
ECDSA<ECP, SHA1>::Verifier verifier(pubKey);
// Java or OpenSSL created signature. It is ANS.1
// SEQUENCE ::= { r INTEGER, s INTEGER }.
const byte derSignature[] = {
0x30, 0x44, 0x02, 0x20, 0x08, 0x66, 0xc8, 0xf1,
0x6f, 0x15, 0x00, 0x40, 0x8a, 0xe2, 0x1b, 0x40,
0x56, 0x28, 0x9c, 0x17, 0x8b, 0xca, 0x64, 0x99,
0x37, 0xdc, 0x35, 0xad, 0xad, 0x60, 0x18, 0x4d,
0x63, 0xcf, 0x4a, 0x06, 0x02, 0x20, 0x78, 0x4c,
0xb7, 0x0b, 0xa3, 0xff, 0x4f, 0xce, 0xd3, 0x01,
0x27, 0x5c, 0x6c, 0xed, 0x06, 0xf0, 0xd7, 0x63,
0x6d, 0xc6, 0xbe, 0x06, 0x59, 0xe8, 0xc3, 0xa5,
0xce, 0x8a, 0xf1, 0xde, 0x01, 0xd5
};
// P1363 'r || s' concatenation. The size is 32+32 due to field
// size for r and s in secp-256. It is not 20+20 due to SHA-1.
SecByteBlock signature(verifier.SignatureLength());
DSAConvertSignatureFormat(signature, signature.size(), DSA_P1363,
derSignature, sizeof(derSignature), DSA_DER);
// Message "Attack at dawn!"
const byte message[] = {
0x41, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x20, 0x61,
0x74, 0x20, 0x64, 0x61, 0x77, 0x6e, 0x21, 0x0a
};
// https://www.cryptopp.com/wiki/Elliptic_Curve_Digital_Signature_Algorithm
bool result = verifier.VerifyMessage(message, sizeof(message), signature, signature.size());
if (result)
std::cout << "Verified message" << std::endl;
else
std::cout << "Failed to verify message" << std::endl;
return 0;
}
And here is the result of running the test program.
$ ./test.exe
Signature (64):
0866C8F16F1500408AE21B4056289C178BCA649937DC35ADAD60184D63CF4A06784CB70BA3FF4FCE
D301275C6CED06F0D7636DC6BE0659E8C3A5CE8AF1DE01D5
Verified message
Here is the setup I used to reproduce cat test.txt | openssl dgst -ecdsa-with-SHA1 -sign sample.key -keyform DER > test.sig. It is from #DivB's question at ECDSA sign with OpenSSL, verify with Crypto++.
$ cat test.txt
Attack at dawn!
$ hexdump -C test.txt
00000000 41 74 74 61 63 6b 20 61 74 20 64 61 77 6e 21 0a |Attack at dawn!.|
00000010
# Create private key in PEM format
$ openssl ecparam -name secp256k1 -genkey -noout -out secp256k1-key.pem
$ cat secp256k1-key.pem
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIO0D5Rjmes/91Nb3dHY9dxmbM7gVfxmB2+OVuLmWMbGXoAcGBSuBBAAK
oUQDQgAEgVNEuirUNCEVdf7nLSBUgU1GXLrtIBeglIbK54s91HlWKOKjk4CkJ3/B
wGAfcYKa+DgJ2IUQSD15K1T/ghM9eQ==
-----END EC PRIVATE KEY-----
# Convert private key to ASN.1/DER format
$ openssl ec -in secp256k1-key.pem -inform PEM -out secp256k1-key.der -outform DER
$ dumpasn1 secp256k1-key.der
0 116: SEQUENCE {
2 1: INTEGER 1
5 32: OCTET STRING
: ED 03 E5 18 E6 7A CF FD D4 D6 F7 74 76 3D 77 19
: 9B 33 B8 15 7F 19 81 DB E3 95 B8 B9 96 31 B1 97
39 7: [0] {
41 5: OBJECT IDENTIFIER secp256k1 (1 3 132 0 10)
: }
48 68: [1] {
50 66: BIT STRING
: 04 81 53 44 BA 2A D4 34 21 15 75 FE E7 2D 20 54
: 81 4D 46 5C BA ED 20 17 A0 94 86 CA E7 8B 3D D4
: 79 56 28 E2 A3 93 80 A4 27 7F C1 C0 60 1F 71 82
: 9A F8 38 09 D8 85 10 48 3D 79 2B 54 FF 82 13 3D
: 79
: }
: }
# Create public key from private key
$ openssl ec -in secp256k1-key.der -inform DER -pubout -out secp256k1-pub.der -outform DER
$ dumpasn1 secp256k1-pub.der
0 86: SEQUENCE {
2 16: SEQUENCE {
4 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
13 5: OBJECT IDENTIFIER secp256k1 (1 3 132 0 10)
: }
20 66: BIT STRING
: 04 81 53 44 BA 2A D4 34 21 15 75 FE E7 2D 20 54
: 81 4D 46 5C BA ED 20 17 A0 94 86 CA E7 8B 3D D4
: 79 56 28 E2 A3 93 80 A4 27 7F C1 C0 60 1F 71 82
: 9A F8 38 09 D8 85 10 48 3D 79 2B 54 FF 82 13 3D
: 79
: }
# Sign the message using the private key
$ cat test.txt | openssl dgst -ecdsa-with-SHA1 -sign secp256k1-key.der -keyform DER > test.sig
# Dump the signature as hex
$ hexdump -C test.sig
00000000 30 44 02 20 08 66 c8 f1 6f 15 00 40 8a e2 1b 40 |0D. .f..o..#...#|
00000010 56 28 9c 17 8b ca 64 99 37 dc 35 ad ad 60 18 4d |V(....d.7.5..`.M|
00000020 63 cf 4a 06 02 20 78 4c b7 0b a3 ff 4f ce d3 01 |c.J.. xL....O...|
00000030 27 5c 6c ed 06 f0 d7 63 6d c6 be 06 59 e8 c3 a5 |'\l....cm...Y...|
00000040 ce 8a f1 de 01 d5 |......|
00000046
# Dump the signature as ASN.1/DER
$ dumpasn1 test.sig
0 68: SEQUENCE {
2 32: INTEGER
: 08 66 C8 F1 6F 15 00 40 8A E2 1B 40 56 28 9C 17
: 8B CA 64 99 37 DC 35 AD AD 60 18 4D 63 CF 4A 06
36 32: INTEGER
: 78 4C B7 0B A3 FF 4F CE D3 01 27 5C 6C ED 06 F0
: D7 63 6D C6 BE 06 59 E8 C3 A5 CE 8A F1 DE 01 D5
: }

By the way, another way around your problem (especially allowing you to avoid the command line) would be to modify the Java code in order to have a way to produce the R and S values, as well as to reproduce the DER encoded values.
For example you can extract the R and S values from the Java signature using those:
public static BigInteger extractR(byte[] signature) throws Exception {
int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
int lengthR = signature[startR + 1];
return new BigInteger(Arrays.copyOfRange(signature, startR + 2, startR + 2 + lengthR));
}
public static BigInteger extractS(byte[] signature) throws Exception {
int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
int lengthR = signature[startR + 1];
int startS = startR + 2 + lengthR;
int lengthS = signature[startS + 1];
return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS));
}
These methods are notably used in Wycheproof to play around with the BigIntegers directly.
These can allow you to reconstruct the P1363 encoding used by CryptoPP in Java, but be careful not to forget the left padding with 0s of the bytearrays. (Otherwise you may have problems when the R or S bytearray is smaller than the expected length.)
And you can also reconstruct the DER encoded signature from big integers using:
public static byte[] derSign(BigInteger r, BigInteger s) throws Exception {
byte[] rb = r.toByteArray();
byte[] sb = s.toByteArray();
int off = (2 + 2) + rb.length;
int tot = off + (2 - 2) + sb.length;
byte[] der = new byte[tot + 2];
der[0] = 0x30;
der[1] = (byte) (tot & 0xff);
der[2 + 0] = 0x02;
der[2 + 1] = (byte) (rb.length & 0xff);
System.arraycopy(rb, 0, der, 2 + 2, rb.length);
der[off + 0] = 0x02;
der[off + 1] = (byte) (sb.length & 0xff);
System.arraycopy(sb, 0, der, off + 2, sb.length);
return der;
}
As you can see, these methods might be translated into C++ code, since they are really basic byte manipulations, but that's another story ;)

Building on top of Lery's excellent answer, I found myself wanting a 64-byte fixed P1363 style signature. The Java solution posted is great, but the r and s values may contain sign bits and therefore result in a 64-66 bytes signature.
In this Kotlin function, I compute the r and s values, and I take only the lower 32 bytes each, and this gave me the 64-byte signature I wanted.
fun generateSignatureFromKeystore(message: ByteArray, privateKey: PrivateKey): ByteArray {
// BouncyCastle's signing doesn't work with Android Keystore's ECPrivateKey
val signatureConfig = Signature.getInstance("SHA256withECDSA").apply {
initSign(privateKey)
update(message)
}
val signature = signatureConfig.sign()
// Convert ASN.1 DER signature to IEEE P1363
val startR = if (signature[1].toUnsignedInt().and(0) != 0) 3 else 2
val lengthR = signature[startR + 1].toUnsignedInt()
val r = signature.copyOfRange(startR + 2, startR + 2 + lengthR).takeLast(32).toByteArray()
val startS = startR + 2 + lengthR
val lengthS = signature[startS + 1].toInt()
val s = signature.copyOfRange(startS + 2, startS + 2 + lengthS).takeLast(32).toByteArray()
return r + s
}
private fun Byte.toUnsignedInt(): Int = toInt().and(0xFF)

Related

Java SSL/TLS Handshake

im writing a small HTTP/S Server for an Embeded Device Framework.
Because i use plain Java Sockets i need to implement the TLS/SSL myself.
For the Client Handshake i wrote following Function:
if (secureIO) {
// Print Message if Client Handshake was correct.
((SSLSocket) clientIO)
.addHandshakeCompletedListener(new HandshakeCompletedListener() {
#Override
public void handshakeCompleted(HandshakeCompletedEvent eventIO) {
logIO.debug(GuardianLog.Type.SUCCESS,
"Handshake with Client "
+ clientIO.getInetAddress().getHostAddress() + " via Method "
+ eventIO + " was correct.");
// Unlock Stream Lock.
lockIO[0] = false;
}
});
// ((SSLSocket) clientIO).setNeedClientAuth(true);
// Session Creation Blocks everything...
((SSLSocket) clientIO).setEnableSessionCreation(true);
// Set Cipher and Protocols for Client.
((SSLSocket) clientIO)
.setEnabledProtocols(((SSLServerSocket) tcpIO).getEnabledProtocols());
((SSLSocket) clientIO)
.setEnabledCipherSuites(
((SSLServerSocket) tcpIO).getEnabledCipherSuites());
// Start Handshake to Client.
((SSLSocket) clientIO).startHandshake();
}
The Problem is, when i opening the Socket Port in the Browser, the Page loads forever.
So i tried to debug the SSLSocket with OPENSSL it seems that the Handshake gets not fully finished.
I thought some Stream gets confused by an Listener on my Server, but i disabled the Input/Output Stream entirely with the lock bool, until the Handshake Complete Listener gets executed.
Some outstanding Debug Traces from the Server have given me this theory.
javax.net.ssl|ALL|1C|Server-Socket|2022-07-08 21:51:57.696 CEST|SSLSessionImpl.java:250|Session initialized: Session(1657309917387|TLS_AES_256_GCM_SHA384)
javax.net.ssl|FINE|1C|Server-Socket|2022-07-08 21:51:57.696 CEST|SSLSocketOutputRecord.java:241|WRITE: TLS13 handshake, length = 50
javax.net.ssl|FINE|1C|Server-Socket|2022-07-08 21:51:57.697 CEST|SSLCipher.java:2013|Plaintext before ENCRYPTION (
0000: 04 00 00 2E 00 01 51 80 F9 1F 1E 31 01 01 00 20 ......Q....1...
0010: E5 5B CF E4 29 3B 0E 9F E4 12 D7 CD 8B 34 2C 22 .[..);.......4,"
0020: 0B 14 45 B3 E9 94 CC 62 64 C3 06 E4 4F 72 82 D3 ..E....bd...Or..
0030: 00 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0040: 00 00 00 ...
)
javax.net.ssl|FINE|1C|Server-Socket|2022-07-08 21:51:57.697 CEST|SSLSocketOutputRecord.java:255|Raw write (
0000: 17 03 03 00 53 6B D3 EE EF C5 DD D2 E3 3F DF 15 ....Sk.......?..
0010: 13 87 A5 9E BB AC 0A 1F 1F 6A 77 50 B1 4D 51 39 .........jwP.MQ9
0020: 4D 0C 00 78 D1 4A D8 78 79 9A 79 7E AD EB 20 80 M..x.J.xy.y... .
0030: 91 C3 A5 14 33 FF 13 01 9B D6 37 7E 3A 7B 9F 7D ....3.....7.:...
0040: 03 E6 59 90 FF 9B E3 63 87 18 FD 84 37 C7 21 CA ..Y....c....7.!.
0050: A7 AC ED 25 C3 05 73 A8 ...%..s.
)
Heres an example of my Read Function, the InputStream is setet after the Socket.accpet() Method:
private void read(InputStream streamIO, java.net.Socket clientIO) {
// todo: Test Performance between execute and submit.
poolIO.execute(new Runnable() {
#Override
public void run() {
try {
// clientIO.isConnected() && !tcpIO.isClosed() &&
while (!shutdownIO && clientIO.isConnected() && !tcpIO.isClosed()) {
// Byte Buffer ho contains read Data.
// #todo: add buffer max size, read until -1 (EOF).
byte[] bufferIO = new byte[streamIO.available()];
// Read Data into Buffer and store (EOF).
int codeIO = streamIO.read(bufferIO);
if (codeIO != 0 || bufferIO.length != 0) {
System.out.println(codeIO);
System.out.println(bufferIO.length);
}
// Check if bytes in the Buffer.
if (bufferIO.length != 0 && streamIO.available() == 0) {
if (binaryIO)
binary(new Socket(clientIO), bufferIO);
if (stringIO)
string(new Socket(clientIO), new String(bufferIO, charsetIO));
}
if (eofIO && (codeIO == -1)) {
break;
}
// Sleep for 100 Milliseconds (CPU Usage)
Thread.sleep(100);
}
streamIO.reset();
streamIO.close();
clientIO.close();
disconnect(new Socket(clientIO));
// Clear Buffer Stream.
// bufferIO = new byte[0];
} catch (IOException | InterruptedException errorIO) {
if (errorIO.getMessage().equalsIgnoreCase("Stream closed.")
|| errorIO.getMessage().equalsIgnoreCase("Connection reset")) {
logIO.debug(GuardianLog.Type.INFO,
"Client with IP " + clientIO.getInetAddress().getHostAddress()
+ " disconnected from Server with Port " + networkIO.getPort()
+ ".");
disconnect(new Socket(clientIO));
} else if (errorIO.getMessage().equalsIgnoreCase("sleep interrupted")) {
logIO.debug(
GuardianLog.Type.WARNING, "Socket Thread interrupted.", errorIO);
} else
logIO.append(
GuardianLog.Type.ERROR, "Socket throw an Error ", errorIO);
}
}
});
}

Blowfish decrypting hex encoded string

I'm trying to decrypt Hex encoded string via Blowfish. But the result is different from the correct one.
String s="a1d0534e4baf9e670bde8670caee8b87"
String decKey = "R=U!LH$O2B#";
Cipher m_decrypt = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
m_decrypt.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decKey.getBytes(),"Blowfish"));
byte[] decrypted = m_decrypt.doFinal(Hex.decodeHex(s.toCharArray()));
Correct result from site: c6 b7 8d 52 31 35 30 34 31 38 38 36 39 37 02 02
My result: -58 -73 -115 82 49 53 48 52 49 56 56 54 57 55
I check the correct byte array with mine on this site http://blowfish.online-domain-tools.com/
The correect result: c6 b7 8d 52 31 35 30 34 31 38 38 36 39 37 02 02
is in hex encoding and contains two bytes of padding.
My result: -58 -73 -115 82 49 53 48 52 49 56 56 54 57 55
in in signed decimal encoding without the padding bytes.
They are the same value just in different encodings where "My result" has had the padding removed as is usual.

Extract .gz files in java

I'm trying to unzip some .gz files in java. After some researches i wrote this method:
public static void gunzipIt(String name){
byte[] buffer = new byte[1024];
try{
GZIPInputStream gzis = new GZIPInputStream(new FileInputStream("/var/www/html/grepobot/API/"+ name + ".txt.gz"));
FileOutputStream out = new FileOutputStream("/var/www/html/grepobot/API/"+ name + ".txt");
int len;
while ((len = gzis.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
gzis.close();
out.close();
System.out.println("Extracted " + name);
} catch(IOException ex){
ex.printStackTrace();
}
}
when i try to execute it i get this error:
java.util.zip.ZipException: Not in GZIP format
how can i solve it? Thanks in advance for your help
Test a sample, correct, gzipped file to see whether the problem lies in your code or not.
There are many possible ways to build a (g)zip file. Your file may have been built differently from what Java's built-in support expects, and the fact that one uncompressor understands a compression variant is no guarantee that Java will also recognize that variant. Please verify exact file type with file and/or other uncompression utilities that can tell you which options were used when compressing it. You may also have a look at the file itself with a tool such as hexdump. This is the output of the following command:
$ hexdump -C lgpl-2.1.txt.gz | head
00000000 1f 8b 08 08 ed 4f a9 4b 00 03 6c 67 70 6c 2d 32 |.....O.K..lgpl-2|
00000010 2e 31 2e 74 78 74 00 a5 5d 6d 73 1b 37 92 fe 8e |.1.txt..]ms.7...|
00000020 ba 1f 81 d3 97 48 55 34 13 7b 77 73 97 78 2b 55 |.....HU4.{ws.x+U|
00000030 b4 44 d9 bc 95 25 2d 29 c5 eb ba ba aa 1b 92 20 |.D...%-)....... |
00000040 39 f1 70 86 99 17 29 bc 5f 7f fd 74 37 30 98 21 |9.p...)._..t70.!|
00000050 29 7b ef 52 9b da 58 c2 00 8d 46 bf 3c fd 02 d8 |){.R..X...F.<...|
00000060 da fe 3f ef 6f 1f ed cd 78 36 1b 4f ed fb f1 ed |..?.o...x6.O....|
00000070 78 3a ba b1 f7 8f ef 6e 26 97 96 fe 1d df ce c6 |x:.....n&.......|
00000080 e6 e0 13 f9 e7 57 57 56 69 91 db 37 c3 d7 03 7b |.....WWVi..7...{|
00000090 ed e6 65 93 94 7b fb fa a7 9f 7e 32 c6 5e 16 bb |..e..{....~2.^..|
In this case, I used standard gzip on this license text. The 1st few bytes are unique to GZipped files (although they do not specify variants) - if your file does not start with 1f 8b, Java will complain, regardless of remaining contents.
If the problem is due to the file, it is possible that other uncompression libraries available in Java may deal with the format correctly - for example, see Commons Compress
import com.horsefly.utils.GZIP;
import org.apache.commons.io.FileUtils;
....
String content = new String(new GZIP().decompresGzipToBytes(FileUtils.readFileToByteArray(fileName)), "UTF-8");
in case someone needs it.

PNG True color with Alpha decoding

I am writing a PNG decoder and I am encountering some weirdness. Going through the PNG file format, I have managed to decode PNGs with Color Index + tRNS (alpha) and True Color + tRNS (alpha) correctly. I am currently not sure why I cannot decode a PNG with True Color with Alpha type PNG. I have verified that my inflate of IDAT chunk is correct. Here's what the chunks looks like:
Width: 256
Height: 256
Bit Depth: 8
Color Type: 6
Compression: 0
Filter: 0
Interlace: 0
Length: 25
Type: tEXt
Data: 53 6f 66 74 77 61 72 65 00 41 64 6f 62 65 20 49 6d 61 67 65 52 65 61 64 79
CRC: 71c9653c
Length: 20690
Type: IDAT
Data: 78 da ec 7d 09 9c 1c 57 99 df f7 7a a6 e7 3e 5a a3 fb ...
CRC: 21550259
The actual data is too long to be printed here. Here's my logic of decoding this, please correct me if I'm wrong:
Inflate all the bytes given in the IDAT chunk
Un-filter the inflated chunks. In this case, all filters are of type 0 and therefore, we simply discard the filter byte.
Since this is color type 6, a pixel is represented by RGBA channels with 1 byte each. This means we need to interpret 4 bytes at a time. The following code is used:
ByteBuffer image = BufferUtil.getDirectByteBuffer(data.length, ByteOrder.BIG_ENDIAN);
int i = 0;
while(i < data.length){
int color = ( (data[i] & 0xff) << 24) | ( (data[i+1] & 0xff) << 16) | ( (data[i+2] & 0xff) << 8) | (data[i+3] & 0xff);
image.putInt(color);
i += 4;
What's strange is that I get mostly RRGGBBAA = 0x00000000 data resulting in a clear image with little color.
The problem is you are neglecting to observe the filtering for each scanline.
From the image provided the decompressed data looks like
1 ffffffff 0 0 0 ...
2 0 0 0 0 0 0 ...
..
the first value in each line conforms to the filter method used [http://www.w3.org/TR/PNG/#9Filters]
the scanlines post processing will look like
ffffffff ffffffff ffffffff ...
ffffffff ffffffff ffffffff ...
...
here is some example code that handles methods 0, 1 and 2.
private static void processScanLine(byte filterValue, byte[] scanLine, byte[] previousScanLine) {
switch(filterValue){
case 0:break;
case 1:
for (int i =4;i<scanLine.length;i++){
scanLine[i] = (byte)(scanLine[i]+scanLine[i-4]);
}
break;
case 2:
for (int i =0;i<scanLine.length;i++){
scanLine[i] = (byte)(scanLine[i]+previousScanLine[i]);
}
break;
}
}

convert txt packet data to pcap format to open it by Wireshark

Hi I am working on application where I have to read live packets
from network work on it. And display it in sophisticated way.
But problem is I have packet but it is in text file, so to open it
by Wireshark I have to convert it in .pcap format.
So how can I convert packet in text to pcap format.
My text file format is like this shown below,
Frame:
Frame: number = 0
Frame: timestamp = 2014-02-13 09:39:11.288
Frame: wire length = 174 bytes
Frame: captured length = 174 bytes
Frame:
Eth: ******* Ethernet - "Ethernet" - offset=0 (0x0) length=14
Eth:
Eth: destination = 01:00:5e:7f:ff:fa
Eth: .... ..0. .... .... = [0] LG bit
Eth: .... ...0 .... .... = [0] IG bit
Eth: source = ec:9a:74:4d:8e:03
Eth: .... ..0. .... .... = [0] LG bit
Eth: .... ...0 .... .... = [0] IG bit
Eth: type = 0x800 (2048) [ip version 4]
Eth:
Ip: ******* Ip4 - "ip version 4" - offset=14 (0xE) length=20 protocol suite=NETWORK
Ip:
Ip: version = 4
Ip: hlen = 5 [5 * 4 = 20 bytes, No Ip Options]
Ip: diffserv = 0x0 (0)
Ip: 0000 00.. = [0] code point: not set
Ip: .... ..0. = [0] ECN bit: not set
Ip: .... ...0 = [0] ECE bit: not set
Ip: length = 160
Ip: id = 0x4CD1 (19665)
Ip: flags = 0x0 (0)
Ip: 0.. = [0] reserved
Ip: .0. = [0] DF: do not fragment: not set
Ip: ..0 = [0] MF: more fragments: not set
Ip: offset = 0
Ip: ttl = 0 [time to live]
Ip: type = 17 [next: User Datagram]
Ip: checksum = 0xB0AA (45226) [correct]
Ip: source = 124.125.80.90
Ip: destination = 239.255.255.250
Ip:
Udp: ******* Udp offset=34 (0x22) length=8
Udp:
Udp: source = 58845
Udp: destination = 1900
Udp: length = 140
Udp: checksum = 0x5154 (20820) [correct]
Udp:
Data: ******* Payload offset=42 (0x2A) length=132
Data:
002a: 4d 2d 53 45 41 52 43 48 20 2a 20 48 54 54 50 2f M-SEARCH * HTTP/
003a: 31 2e 31 0d 0a 48 6f 73 74 3a 32 33 39 2e 32 35 1.1..Host:239.25
004a: 35 2e 32 35 35 2e 32 35 30 3a 31 39 30 30 0d 0a 5.255.250:1900..
005a: 53 54 3a 75 72 6e 3a 73 63 68 65 6d 61 73 2d 75 ST:urn:schemas-u
006a: 70 6e 70 2d 6f 72 67 3a 64 65 76 69 63 65 3a 57 pnp-org:device:W
007a: 41 4e 43 6f 6e 6e 65 63 74 69 6f 6e 44 65 76 69 ANConnectionDevi
008a: 63 65 3a 31 0d 0a 4d 61 6e 3a 22 73 73 64 70 3a ce:1..Man:"ssdp:
009a: 64 69 73 63 6f 76 65 72 22 0d 0a 4d 58 3a 33 0d discover"..MX:3.
00aa: 0a 0d 0a 00
Wireshark provides a command line pcap converter for Text Files:
https://www.wireshark.org/docs/man-pages/text2pcap.html
AutoHotkey solution:
; Change appropriate file locations
Run, %A_ProgramFiles%\ethereal\text2pcap.exe c:\test.txt c:\testconv.cap,%A_ProgramFiles%\ethereal
If you want to do a fully automated solution you can modify this function which actively watches a directory for file changes/creation.
http://www.autohotkey.com/board/topic/41653-watchdirectory/
If you have raw packets captured you can write them directly to pcap file format (see man 5 pcap-savefile) or use hexdump/xxd+text2pcap utility as ahkcoder recommends. Text2pcap also supports generation of dummy L2-4 headers (ethernet, ip, tcp/udp/sctp).
If you have only text representation, you can either reconstruct packet from it (so, generate all appropriate headers for each protocol used in your system) or adjust hex dump part offsets (to begin from 0000) and feed it to text2pcap.

Categories