Crypto++ and Compressed EC keys - c++

How can I generate compressed ECDSA keys in Crypto++?
AutoSeededRandomPool prng;
ECDSA<ECP, SHA1>::PrivateKey privateKey;
ECDSA<ECP, SHA1>::PublicKey publicKey;
privateKey.Initialize( prng, CryptoPP::ASN1::secp256r1());
const Integer& x1 = privateKey.GetPrivateExponent();
cout << "priv: " << std::hex << x1 << endl;
privateKey.MakePublicKey( publicKey );
const ECP::Point& q = publicKey.GetPublicElement();
const Integer& qx = q.x;
const Integer& qy = q.y;
cout << "pub x: " << std::hex << qx << endl;
cout << "pub y: " << std::hex << qy << endl;
This code generates a keypair and prints the X and Y components of the public key.
I need to know if there is a way to print the Y component of the compressed key, or if I need to generate it from the uncompressed y component. If I need to generate it, can someone link me to a good explanation of how to work with the Integer class?

How can I generate compressed ECDSA keys in CryptoPP?
You don't create a compressed key. You generate a public key, and then you compress it if that's what is required. From How to construct a public ECDSA key with point compression turned on? on the Crpyto++ user group:
ECDSA<ECP, SHA1>::Verifier verifier(...);
verifier.AccessKey().AccessGroupParameters().SetPointCompression(true);
In your case, it will be:
publicKey.AccessGroupParameters().SetPointCompression(true);
since verifier.AccessKey() returns the ECDSA public key.
I need to know if there is a way to print the Y component of the compressed key
Compression is a presentation format option or optimization. You can't print the Y component on a serialized key with compression because its not there (see the ASN.1 dumps below).
With compression on, the Y "shorthand" is going to be 1 or -1, depending on the sign of the component (the sign indicates what quadrant the point is in). The idea is someone sends you a {1,X} pair or {-1,X} pair and you can solve for Y because you know which quadrant it should be in. If Y is only allowed to be positive, you only need to serialize {X} (and not {-1,X} or {1,X}). (I did not dive into the books or standards, so there may be some errata here).
... or if I need to generate it from the uncompressed y component. If I need to generate it, can someone link me to a good explanation of how to work with the Integer class?
I have no idea what you're talking about at here. Point compression affects presentation. If you turn on point compression and fetch Y, you will still get Y out. You can't compute on a compressed point. You need the X and Y coordinates.
Add the following to your program:
publicKey.AccessGroupParameters().SetPointCompression(false);
ByteQueue q1;
publicKey.Save(q1);
cout << "Uncompressed size: " << dec << q1.MaxRetrievable() << endl;
publicKey.AccessGroupParameters().SetPointCompression(true);
ByteQueue q2;
publicKey.Save(q2);
cout << "Compressed size: " << dec << q2.MaxRetrievable() << endl;
Here's what I got for the output:
$ ./cryptopp-test.exe
priv: 4ce30d22d9593d9c7f4406eda1ce0740c7486106374d0abe7e352e1d5b1d5622h
pub x: 41a9bc936b6d1dd3a1ded997d7da08f1df990e9b50f9b58e9e4fd9319758ea34h
pub y: 4ad39ffb79c402063a99ecbc0cac8fde606db6764ace90933feee5f8d65937a2h
Uncompressed size: 311
Compressed size: 246
If you fetch Y after turning on point compression, you will still get 4ad39ffb79c402063a99ecbc0cac8fde606db6764ace90933feee5f8d65937a2h because compression affects presentation.
Now, add the following to dump the uncompressed and compressed key:
FileSink fs1("key-1.der", true);
q1.TransferTo(fs1);
FileSink fs2("key-2.der", true);
q2.TransferTo(fs2);
The keys are dumped in ASN.1's DER encoding and conform to Certicom's SEC 1: Elliptic Curve Cryptography (and to a lesser extent, ANSI 9.62 and RFC 5480, ECC SubjectPublicKeyInfo Format - see below on the Field Element's OCTET STRING vs BIT STRING).
You can run Peter Gutmann's dumpasn1 on them:
$ dumpasn1.exe key-1.der
0 307: SEQUENCE {
4 236: SEQUENCE {
7 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
16 224: SEQUENCE {
19 1: INTEGER 1
22 44: SEQUENCE {
24 7: OBJECT IDENTIFIER prime-field (1 2 840 10045 1 1)
33 33: INTEGER
: 00 FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00
: 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF
: FF
: }
68 68: SEQUENCE {
70 32: OCTET STRING
: FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00 00
: 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FC
104 32: OCTET STRING
: 5A C6 35 D8 AA 3A 93 E7 B3 EB BD 55 76 98 86 BC
: 65 1D 06 B0 CC 53 B0 F6 3B CE 3C 3E 27 D2 60 4B
: }
138 65: OCTET STRING
: 04 6B 17 D1 F2 E1 2C 42 47 F8 BC E6 E5 63 A4 40
: F2 77 03 7D 81 2D EB 33 A0 F4 A1 39 45 D8 98 C2
: 96 4F E3 42 E2 FE 1A 7F 9B 8E E7 EB 4A 7C 0F 9E
: 16 2B CE 33 57 6B 31 5E CE CB B6 40 68 37 BF 51
: F5
205 33: INTEGER
: 00 FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF
: FF BC E6 FA AD A7 17 9E 84 F3 B9 CA C2 FC 63 25
: 51
240 1: INTEGER 1
: }
: }
243 66: BIT STRING
: 04 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
: F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
: 34 4A D3 9F FB 79 C4 02 06 3A 99 EC BC 0C AC 8F
: DE 60 6D B6 76 4A CE 90 93 3F EE E5 F8 D6 59 37
: A2
: }
$ dumpasn1.exe key-2.der
0 243: SEQUENCE {
3 204: SEQUENCE {
6 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
15 192: SEQUENCE {
18 1: INTEGER 1
21 44: SEQUENCE {
23 7: OBJECT IDENTIFIER prime-field (1 2 840 10045 1 1)
32 33: INTEGER
: 00 FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00
: 00 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF
: FF
: }
67 68: SEQUENCE {
69 32: OCTET STRING
: FF FF FF FF 00 00 00 01 00 00 00 00 00 00 00 00
: 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FC
103 32: OCTET STRING
: 5A C6 35 D8 AA 3A 93 E7 B3 EB BD 55 76 98 86 BC
: 65 1D 06 B0 CC 53 B0 F6 3B CE 3C 3E 27 D2 60 4B
: }
137 33: OCTET STRING
: 03 6B 17 D1 F2 E1 2C 42 47 F8 BC E6 E5 63 A4 40
: F2 77 03 7D 81 2D EB 33 A0 F4 A1 39 45 D8 98 C2
: 96
172 33: INTEGER
: 00 FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF
: FF BC E6 FA AD A7 17 9E 84 F3 B9 CA C2 FC 63 25
: 51
207 1: INTEGER 1
: }
: }
210 34: BIT STRING
: 02 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
: F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
: 34
: }
Notice the differences:
# key-1.der
243 66: BIT STRING
: 04 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
: F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
: 34 4A D3 9F FB 79 C4 02 06 3A 99 EC BC 0C AC 8F
: DE 60 6D B6 76 4A CE 90 93 3F EE E5 F8 D6 59 37
: A2
versus:
# key-2.der
210 34: BIT STRING
: 02 41 A9 BC 93 6B 6D 1D D3 A1 DE D9 97 D7 DA 08
: F1 DF 99 0E 9B 50 F9 B5 8E 9E 4F D9 31 97 58 EA
: 34
: }
The first has two Integers encoded, while the second has one Integer encoded. The common value is 41 A9 BC 93 ... 97 58 EA 34, and that's your pub x above. The missing string from key-2 is 4A D3 9F FB ... D6 59 37 A2, and that's the pub y above. For completeness, the values are encoded as either {X,Y} or {X}, and not ASN.1's encoding of integers.
The final difference is the first octet of the BIT STRING: 02 versus 04 (or 03). 04 indicates its an uncompressed point. From RFC 5480, Section 2.2:
The first octet of the OCTET STRING indicates whether the key is
compressed or uncompressed. The uncompressed form is indicated
by 0x04 and the compressed form is indicated by either 0x02 or
0x03 (see 2.3.3 in [SEC1]). The public key MUST be rejected if
any other value is included in the first octet.
And after looking at the standard and section 2.2, Crypto++ may have a bug: its writing a BIT STRING, but the standard is clearly discussing a OCTET STRING.
EDIT 1: It appears this is a Crypto++ bug under ANSI 9.62, too. Section 6.2, Syntax for Finite Field Elements and Elliptic Curve Points (p. 20)
A finite field element shall be represented by a value of type FieldElement:
FieldElement ::= OCTET STRING
The value of FieldElement shall be the octet string representation of a field
elementfollowing the conversion routine in Section 4.3.1.
An elliptic curve point shall be represented by a value of type ECPoint:
ECPoint ::= OCTET STRING
EDIT 2: Crypto++ is using the format specified by Certicom's SEC 1: Elliptic Curve Cryptography. Appendix C (page 77) states:
Finally, a specific field element is represented by the following type
FieldElement ::= OCTET STRING
whose value is the octet string obtained from the conversion routines
given in Section 2.3.5.

Related

Example of LUC algorithm with Crypto++

I am looking for an example of LUC algorithm, but I can't find anything. I know that it is in Crypto++, but I don't know C++ too well to use it.
I look for an example of algorithm of LUC...
It kind of depends on what you want to do. You might want to browse luc.h to see some of the things Crypto++ offers for LUC. There's a LUCES, a LUCSS and a LUC_IES. The *ES is encryption scheme, the *SS is a signature scheme, and the *IES is an integrated encryption scheme (which includes a key agreement algorithm and mask function).
Generally speaking, LUC is a public key encryption system. Using it is like using any other public key encryption system offered by Crypto++. That's because all the public key encryption systems inherit from the same classes (more correctly, base interfaces). You can see the design in the comments for file pubkey.h.
$ grep -R LUCES *
...
typedef LUCES<OAEP<SHA> >::Decryptor LUCES_OAEP_SHA_Decryptor;
typedef LUCES<OAEP<SHA> >::Encryptor LUCES_OAEP_SHA_Encryptor;
And that's pretty much all you need, though you may not know it.
Here's the easier problem to solve. How do you perform RSA encryption in Crypto++?
$ grep -R RSAES *
...
typedef RSAES<PKCS1v15>::Decryptor RSAES_PKCS1v15_Decryptor;
typedef RSAES<PKCS1v15>::Encryptor RSAES_PKCS1v15_Encryptor;
typedef RSAES<OAEP<SHA> >::Decryptor RSAES_OAEP_SHA_Decryptor;
typedef RSAES<OAEP<SHA> >::Encryptor RSAES_OAEP_SHA_Encryptor;
If you find an RSAES_PKCS1v15_Decryptor or RSAES_OAEP_SHA_Decryptor example, you just copy/replace with LUCES_OAEP_SHA_Decryptor and it will work just fine. And if you find an RSAES_PKCS1v15_Encryptor or RSAES_OAEP_SHA_Encryptor example, you just copy/replace with LUCES_OAEP_SHA_Encryptor and it will work just fine.
You can find the examples of using RSAES_OAEP_SHA_Encryptor and RSAES_OAEP_SHA_Decryptor on the Crypto++ wiki page for RSA Encryption Schemes. Or you can use the ECIES examples at Elliptic Curve Integrated Encryption Scheme (remember, all the public key systems inherit from the same base interfaces, so they all have the same methods and you use them the same way).
This should get you started. It creates a private key, saves it, then creates a public key, and saves it.
try
{
AutoSeededRandomPool prng;
FileSink fs1("lucs-private.der", true);
FileSink fs2("lucs-public.der", true);
InvertibleLUCFunction params;
params.GenerateRandomWithKeySize(prng, 2048);
LUC::PrivateKey privateKey(params);
privateKey.DEREncode(fs1);
LUCES_OAEP_SHA_Decryptor decryptor(privateKey);
// ...
LUC::PublicKey publicKey(params);
publicKey.DEREncode(fs2);
LUCES_OAEP_SHA_Encryptor encryptor(publicKey);
// ...
}
catch(CryptoPP::Exception& ex)
{
cerr << ex.what() << endl;
}
If you don't want to use InvertibleLUCFunction, the do something like this to generate the key. Note: RSA has an InvertibleRSAFunction.
LUC::PrivateKey privateKey;
privateKey.Initialize(prng, 2048);
...
LUC::PublicKey publicKey(privateKey);
...
An here's yet another way to do it:
FileSink fs1("lucs-private.der", true);
FileSink fs2("lucs-public.der", true);
LUCES_OAEP_SHA_Decryptor decryptor;
decryptor.AccessKey().Initialize(prng, 2048);
decryptor.AccessKey().DEREncode(fs1);
...
LUCES_OAEP_SHA_Encryptor encryptor(decryptor);
encryptor.AccessKey().DEREncode(fs2);
...
And here's a dump of the private key created by the test program:
$ dumpasn1 lucs-private.der
0 662: SEQUENCE {
4 1: INTEGER 0
7 257: INTEGER
: 00 B8 7A CA 6A 61 D9 CF 2F D8 89 5C A4 7D 74 7B
: AC F5 10 4C 3D 95 BF DD 2E F5 4E E5 F4 20 CF CD
: 44 7F C7 27 41 48 6B 83 E0 7C D9 66 16 8D 54 36
: 97 B9 CE 2D 80 A6 F6 E5 25 87 83 6E B9 41 45 DC
: 2A EB EC 4E EC D9 C0 17 B4 E0 04 F0 58 61 60 F8
: 87 18 27 16 58 BA 56 4E DD 9B C8 CD 18 46 28 38
: A2 6A A6 14 36 D0 A6 FF 9C B8 A8 B5 0F 3A 11 B5
: 00 08 44 B3 31 58 AF 01 F8 57 17 E8 FC 68 B2 5F
: [ Another 129 bytes skipped ]
268 1: INTEGER 17
271 129: INTEGER
: 00 C8 DF 47 D0 B2 6F C2 1A E4 B7 E8 3D 12 BB FF
: 04 F7 34 40 A0 0E ED DC F7 24 7B D9 46 EE 10 C4
: D5 E2 9C 93 05 CF 13 53 40 F4 50 EC 1F 6D D7 33
: FF FF 46 42 88 8D FC F4 EE 7F 0C 8B 71 71 51 D2
: 3C 32 E3 9A 11 B7 D8 CF EA 10 B2 07 49 3F 93 CD
: A0 3F 71 A9 23 27 35 1F 6A C9 1D FE CE 24 75 33
: 8F 53 71 B9 0B DE BC 05 93 98 A3 EA 94 8E 04 B1
: 29 A1 4F 4C 82 34 7A 08 3A 0E 07 98 8B 00 30 D7
: 5B
403 129: INTEGER
: 00 EB 1B D0 EF 5C 0F FC FC B7 56 A7 70 8C AA B7
: A6 90 C8 1F AA AD A0 0B 66 E5 33 75 F2 BE 68 35
: 29 2E 57 AC E0 E0 C8 04 A7 C4 13 1D 10 30 8B 50
: 20 17 0C 83 A7 14 4A 7D 25 31 77 50 66 08 36 13
: BE 9D C0 4E F4 44 74 7A BB D2 92 D0 F7 AE 7C EB
: 8E 84 5C 27 61 2C C9 7A D1 D0 C5 A0 13 98 96 E3
: 76 CD B0 E7 E8 7E 4E 0A 2D 00 86 07 57 DB 8A 51
: 1E 59 76 EA 88 44 4D DA F3 D6 AB 75 CB A6 45 F3
: F3
535 128: INTEGER
: 2E 6A AA BA B4 E8 DD 11 2D 31 A4 D5 F7 08 AB E3
: 1A 9A 15 58 AE C8 59 BE C4 75 85 90 6D 5D A4 18
: 39 27 8F FF 1C 9A FD 0F 0C 29 05 98 9C 16 FE 84
: A4 5C 85 15 F7 98 E6 D5 5B 23 CA 2F A2 27 8A 00
: 6E B1 BB 02 6E 93 53 85 30 30 61 F5 1C 49 5D 19
: EF DF CD 6F 11 7C 6D DC AE F6 A2 06 53 BB 7E 03
: C3 E5 4E E9 59 E0 D8 5F C3 28 0E E0 17 5C 63 6E
: 8E A6 18 FC AD A5 9B 08 D1 8B 7B 28 9D E2 CF E2
: }
0 warnings, 0 errors.

RSAES_OAEP_SHA_Decryptor MaxPlaintextLength returning zero

I have to write a small authentication server that, when a client connects, sends a RSA public exponent and modulus to it, and the client returns the username and password encrypted with them. The part where I get the exponent and modulus works fine, the client receives them, and sends the encoded block back; that's not a problem. The problem is in decoding it: the RSA Decryptor always returns 0 as MaxPlaintextLength, and no matter how many different ways I try to move the data around, I can't get it to work.
I'm providing hex dumps of the different parts after the code.
// These are static in the namespace to keep the key loaded.
static CryptoPP::AutoSeededRandomPool rsaRng;
static CryptoPP::InvertibleRSAFunction rsaParameters;
static CryptoPP::RSA::PrivateKey rsaPrivateKey(rsaParameters);
// This is done when the client connects.
{
rsaPrivateKey.GenerateRandomWithKeySize(rsaRng, 1024);
// This is where GetPublicExponent() and GetModulus() are
// encoded and sent to the client. They are sent correctly
// and I receive the encrypted data in a char buffer.
}
// This runs when I receive the encrypted data, which starts
// at &dataBuffer[7] and has a length of rsaPayloadLen.
{
int rsaPlainSize;
byte *rsaBuffer;
rsaBuffer = new byte[rsaPayloadLen];
memcpy(&rsaBuffer[0], &dataBuffer[7], rsaPayloadLen);
CryptoPP::SecByteBlock rsaCypher(rsaBuffer, rsaPayloadLen);
CryptoPP::RSAES_OAEP_SHA_Decryptor rsaDecryptor(rsaPrivateKey);
// At this point I inspected rsaCypher and it does contain the
// expected binary data, and rsaCypher.size() returns 256.
rsaPlainSize = rsaDecryptor.MaxPlaintextLength(rsaCypher.size());
// rsaPlainSize is 0. I have no idea why!
}
Hex dumps of everything at the time of calling MaxPlaintextLength:
rsaPrivateKey.GetPublicExponent():
000000: 11 .
rsaPrivateKey.GetPrivateExponent():
000000: 10 7a fd fd 9e a9 72 8c c3 5d 5b 80 e8 f4 6f bc .z....r..][...o.
000010: bc 6a 7a 51 4f 9f af d3 e4 76 a5 4a 9d fe 17 37 .jzQO....v.J...7
000020: 03 cf 82 24 33 e2 a0 d8 97 26 0a 6b ac 9d b1 de ...$3....&.k....
000030: 39 d5 3a 93 aa 65 66 be 17 43 3c 00 20 77 68 0a 9.:..ef..C<. wh.
000040: ac 2f 77 1e b8 c4 7f 64 52 54 7c 17 54 b6 e6 a4 ./w....dRT|.T...
000050: 95 49 60 7b 7b 16 6a 41 72 54 03 a2 2d 3a 80 8b .I`{{.jArT..-:..
000060: aa 74 fa 77 22 5d 0a d9 81 b2 b2 48 01 db 43 e8 .t.w"].....H..C.
000070: 16 1c c4 c3 a6 bf 45 7e 90 d3 6a 37 10 40 9f 71 ......E~..j7.#.q
rsaPrivateKey.GetModulus():
000000: d2 20 26 61 a6 f0 74 82 ba e6 4e ab 9a 2c 90 a6 . &a..t...N..,..
000010: 62 4d 97 8c b7 34 01 cd a0 e8 bb 77 5e 67 a7 fd bM...4.....w^g..
000020: 70 95 bb 4d 95 89 82 c9 87 25 04 dc d8 da 9b d1 p..M.....%......
000030: 61 5e aa da bc 8c dd f7 a8 99 3d 01 9d f2 6e 89 a^........=...n.
000040: e4 75 ec 91 31 e9 86 f4 da 43 4a ca a4 66 6b 04 .u..1....CJ..fk.
000050: c2 c9 a1 18 1d fa 81 b0 6e ef a5 13 04 44 88 89 ........n....D..
000060: 42 41 be 9c 7c 77 75 96 50 07 70 ad eb 60 e5 05 BA..|wu.P.p..`..
000070: aa a8 d8 27 03 28 cf bb c7 f5 cb 0d b3 b3 96 7f ...'.(..........
rsaPrivateKey.GetPrime1():
000000: d7 9e af ac e4 04 42 e4 58 9c 39 19 0e 56 7c ef ......B.X.9..V|.
000010: b3 bf b6 26 73 25 d8 ab d7 5e d1 e0 56 49 ae 66 ...&s%...^..VI.f
000020: c4 d8 81 bc d0 be c2 ef f4 6a 09 72 ef 72 35 7e .........j.r.r5~
000030: 15 f4 f9 3b f8 be f9 3a a1 0d 3e d0 eb c8 34 11 ...;...:..>...4.
rsaPrivateKey.GetPrime2():
000000: f9 7a 0e 1c 9a 1b eb d1 67 f1 e3 88 1d f3 f1 62 .z......g......b
000010: 9f a2 5c cb 49 76 de 42 25 e1 a4 de ed 50 f3 2d ..\.Iv.B%....P.-
000020: c0 15 c3 70 b5 96 68 51 25 f7 06 24 e4 43 0d b8 ...p..hQ%..$.C..
000030: 7a c5 12 2c 7c 63 20 73 70 61 01 fe b8 b3 71 8f z..,|c spa....q.
Plain text buffer that was encrypted:
000000: 73 74 72 69 6e 67 62 75 66 66 65 72 00 00 00 00 stringbuffer....
000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..............
rsaCypher:
000000: 0e 9e bd 34 10 16 98 a5 b8 e4 0c 9b 4f 23 71 6d ...4........O#qm
000010: af d6 e8 c1 4d 97 b9 32 cb 25 eb 01 fe 4f 5c 79 ....M..2.%...O\y
000020: 2d d8 32 c4 4f fa e9 2e 58 dd fd 37 7f 08 97 d8 -.2.O...X..7....
000030: 95 bb 6f 04 46 fa 83 77 05 01 43 75 ca be b4 4a ..o.F..w..Cu...J
000040: 60 f9 e7 4a 91 3d bc ac fb e9 41 f3 9d b7 df d3 `..J.=....A.....
000050: a7 03 80 3a 7f 35 98 46 ca 06 b1 f3 d1 7b 56 83 ...:.5.F.....{V.
000060: 1b 00 7d 97 59 39 be 46 d5 cf 6d 2c b3 a7 8e 30 ..}.Y9.F..m,...0
000070: 39 ca ca d5 59 a2 71 43 e7 7e 75 b3 3c d6 a3 a5 9...Y.qC.~u.<...
000080: aa 89 e3 e9 32 e1 a9 c1 a5 a8 f5 66 be 7f c9 ba ....2......f....
000090: 65 35 0f 61 a0 d4 fa c7 ac 8e 28 7c 39 26 3f 01 e5.a......(|9&?.
0000a0: 34 ad 82 69 5e c4 ab 92 48 47 42 04 02 48 79 c4 4..i^...HGB..Hy.
0000b0: 39 6e f2 2c 7c 19 71 34 36 38 1c eb c1 f2 33 f0 9n.,|.q468....3.
0000c0: 49 b9 7e bb c3 16 ed d7 f7 3e 10 a7 cc 2b 8c 31 I.~......>...+.1
0000d0: f1 17 c7 a5 49 ce dd a3 c6 e2 9c 3c 2f 37 e4 97 ....I......</7..
0000e0: ac b7 24 17 b3 f8 75 6f 2a 85 cb 23 7a e1 77 72 ..$...uo*..#z.wr
0000f0: 02 0b 90 28 9b 9b ff 5d 6f 9b 11 11 d3 8b dd 4b ...(...]o......K
rsaCypher.size(): 256
rsaDecryptor.MaxPlaintextLength(rsaCypher.size()): 0
I'm really completely at a loss and the only reason I've spent the whole weekend fighting this is because I'm going to need CryptoPP later for Blowfish and Adler32, otherwise I would have just used another RSA library.
RSAES_OAEP_SHA_Decryptor MaxPlaintextLength returning zero...
Your calculation of rsaPayloadLen is probably not correct. I would suggest you check the size of the ciphertext before you transmit it and after you recover it. I think its size is rsaPayloadLen in you code above.
From the comments in cryptlib.h:
//! maximum length of plaintext for a given ciphertext length
/*! \note This function returns 0 if ciphertextLength is not valid (too long or too short). */
virtual size_t MaxPlaintextLength(size_t ciphertextLength) const =0;
I cannot duplicate when I take plain text, encrypt it, and then pass ciphertext.size() into MaxPlaintextLength. I can duplicate if I pass ciphertext.size() - 1 into MaxPlaintextLength.
As a work around to get you a little further along, you might try using FixedMaxPlaintextLength(). It takes no arguments and only depends upon the public key length. You can use it to find the largest buffer based on the key. But you could fail on decryption.
You should probably show us your encryption code, too. You might not be sizing a buffer correctly.
The whole problem was the key size. The doc said I should use a 1024-bit key, but the other program was expecting a 1152-byte key; apparently that change was never documented. Everything works fine after changing a single line:
rsaPrivateKey.GenerateRandomWithKeySize(rsaRng, 1152);
Leaving this answer here in case someone else ever has this problem. Check the key sizes, and don't trust the documentation!

implementing MSCHAPv2 algorithm in python

I am trying to write a brute-force dictionary attack on MS-CHAPv2 using python. The two pieces of data that I'm giving to the script are hex representations of the 16-byte Client Challenge Hash and the 24-byte Client Challenge Response. Using a dictionary file, I am generating the Responses using the MS-CHAPv2 algorithm:
Convert the client's password (dictionary entry) to little endian Unicode (16-bit).
Hash the converted password with MD4 --> NT_hash (16 bytes long).
Pad NT_hash with 0's to 21 bytes (add five 0's).
Split NT_hash into three 7-byte chunks ([:14], [14:28], and [28:]).
Add odd-parity values to each byte of each chunk, creating three 8-byte keys.
Encrypt the 16-byte Client Challenge Hash three times with DES, each time with a
different 8-byte key from step 5.
Concatenate the results from step 6 into a response to compare with the original
Client Challenge Response.
The problem I'm having is actually with the first two steps. I have tried several combinations of UTF encoding with various MD4 python implementations with some strange results. What is perplexing me is that in some combinations, I achieve the correct NT hash of some of my passwords, but not others. I'm using the following website to check my hashes:
http://www.arsitech.com/cryptography/windows/password/
Can anyone tell me exactly what hashing function I should be using and/or clarify the inconsistencies I'm discovering? My code (most of it) and example output (using a small dictionary of 11 words) are shown below if that helps. The last entry in the output computes the NT hash for the password "SecREt01", and it matches what this forum post has:
http://www.waraxe.us/ftopic-3900-days0-orderasc-30.html
...but none of the others are right. HELP!
SOURCE CODE
# NOTE: these values came from a user with the password "frog"
user = "user1"
CCH16 = "9c:27:2b:1f:3c:be:53:00"
CCH16 = HexToByte(CCH16)
CCR24 = "e9:cc:b4:9a:08:46:30:8b:4e:44:17:e7:cb:a9:af:4d:85:09:8b:89:4f:8a:18:d6"
CCR24 = CCR24.replace(':', ' ')
CCR24 = CCR24.upper()
print "CCR24 --> ", CCR24 # Client Challenge Response
# Initialize variables for loop
password = ""
password_found = False
# Find password
for guess in dictionary:
print "Guess ---> ", guess
# Create nt_hash for this guess using MD4 hashing algorithm.
# TRYING TO ENCODE guess
uGuess = guess.encode('utf-16le')
print "uGuess --> ", uGuess
byteUGuess = bytes(uGuess)
print "byteUGuess --> ", byteUGuess
hexByteUGuess = ByteToHex(byteUGuess)
print "hexByteUGuess --> ", hexByteUGuess
# VARIOUS MD4 IMPLEMENTATIONS
#nt_hash = MD4.new(hexByteUGuess).hexdigest()
#nt_hash = hashlib.new('md4', hexByteUGuess).hexdigest()
nt_hash = nthash.encrypt(guess)
#nt_hash = hashlib.new('md4', uGuess).hexdigest()
#nt_hash = hmac.new(digest, user.upper().encode('utf-16le')).hexdigest()
print " nt_hash = ", nt_hash
# Split nt_hash into three DES keys.
# Add the parity bits to the DES keys to make them 8-bytes each.
des_key_1 = HexToByte(addParity(nt_hash[0:14]))
des_key_2 = HexToByte(addParity(nt_hash[14:28]))
des_key_3 = HexToByte(addParity(nt_hash[28:] + "0000000000"))
print " des_key_1 = ", ByteToHex(des_key_1)
print " des_key_2 = ", ByteToHex(des_key_2)
print " des_key_3 = ", ByteToHex(des_key_3)
# Create DES encryption objects with keys.
des_1 = DES.new(des_key_1, DES.MODE_ECB)
des_2 = DES.new(des_key_2, DES.MODE_ECB)
des_3 = DES.new(des_key_3, DES.MODE_ECB)
# Calculate 24-byte Client Challenge Response for this guess
# with the DES objects and the 16-byte Client Challenge Hash.
ccr24_part1 = des_1.encrypt(CCH16)
ccr24_part2 = des_2.encrypt(CCH16)
ccr24_part3 = des_3.encrypt(CCH16)
ccr24_guess = ByteToHex(ccr24_part1 + ccr24_part2 + ccr24_part3)
print " ccr24_part1 = ", ByteToHex(ccr24_part1)
print " ccr24_part2 = ", ByteToHex(ccr24_part2)
print " ccr24_part3 = ", ByteToHex(ccr24_part3)
print " ccr24 --> ", ccr24_guess
print "CCR24 -----> ", CCR24, "\n"
# Compare the guess (ccr24_guess) with the original (CCR24).
if ccr24_guess == CCR24:
password_found = True
password = guess
break
# If the password was found, display it.
# Otherwise, display fail message.
if password_found == True:
print "Success - Password found!"
print " - PASSWORD --> ", password
else:
print "Failure - Dictionary exhausted..."
print " - Password not found."
EXAMPLE OUTPUT
CCR24 --> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> skate
uGuess --> s k a t e
byteUGuess --> s k a t e
hexByteUGuess --> 73 00 6B 00 61 00 74 00 65 00 0A 00
nt_hash = e4a8e60472df5891903f148b212e2100
des_key_1 = E5 54 38 C1 46 97 7C B0
des_key_2 = 91 C8 0E E3 49 58 85 5D
des_key_3 = 20 80 01 01 01 01 01 01
ccr24_part1 = AB C0 E5 72 51 8B 9C 23
ccr24_part2 = 23 1E 04 09 51 71 8D 35
ccr24_part3 = 8F 17 C3 5A 08 B8 DC 7B
ccr24 --> AB C0 E5 72 51 8B 9C 23 23 1E 04 09 51 71 8D 35 8F 17 C3 5A 08 B8 DC 7B
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> love
uGuess --> l o v e
byteUGuess --> l o v e
hexByteUGuess --> 6C 00 6F 00 76 00 65 00 0A 00
nt_hash = afe622205005339e583f020ced5596b7
des_key_1 = AE F2 89 45 04 80 15 67
des_key_2 = 9E 2C 0E E0 20 67 B5 AB
des_key_3 = 97 5B C1 01 01 01 01 01
ccr24_part1 = 97 51 2E AB 79 15 FD A6
ccr24_part2 = 5E 05 25 3D 9D 7C 92 D0
ccr24_part3 = 54 0D 1F D8 18 E9 2E E3
ccr24 --> 97 51 2E AB 79 15 FD A6 5E 05 25 3D 9D 7C 92 D0 54 0D 1F D8 18 E9 2E E3
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> dry
uGuess --> d r y
byteUGuess --> d r y
hexByteUGuess --> 64 00 72 00 79 00 0A 00
nt_hash = 45f15741ac05cfa965f3ee726f38c116
des_key_1 = 45 F8 54 E9 1A 61 16 9E
des_key_2 = A8 B3 7C 7C E6 92 BC 70
des_key_3 = C1 8A 80 01 01 01 01 01
ccr24_part1 = E0 E5 5C D3 5B 6B 0C 0B
ccr24_part2 = 16 18 F9 DE 53 59 AA BA
ccr24_part3 = 17 62 17 A1 93 88 2F 38
ccr24 --> E0 E5 5C D3 5B 6B 0C 0B 16 18 F9 DE 53 59 AA BA 17 62 17 A1 93 88 2F 38
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> music
uGuess --> m u s i c
byteUGuess --> m u s i c
hexByteUGuess --> 6D 00 75 00 73 00 69 00 63 00 0A 00
nt_hash = bf8704c94ab6b72ba63f9e8d3354c658
des_key_1 = BF C2 C1 98 94 54 DA 6E
des_key_2 = 2A D3 8F F2 E9 68 CD A8
des_key_3 = C7 2C 01 01 01 01 01 01
ccr24_part1 = 42 E1 2F FF D0 26 2F D9
ccr24_part2 = 3A E1 52 CD 98 D8 65 F2
ccr24_part3 = FC 0A E7 CC 99 E0 B2 26
ccr24 --> 42 E1 2F FF D0 26 2F D9 3A E1 52 CD 98 D8 65 F2 FC 0A E7 CC 99 E0 B2 26
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> german
uGuess --> g e r m a n
byteUGuess --> g e r m a n
hexByteUGuess --> 67 00 65 00 72 00 6D 00 61 00 6E 00 0A 00
nt_hash = 0964cddced56685197ed7271804a903a
des_key_1 = 08 B3 32 BA CE 6B 58 D0
des_key_2 = 51 CB FB AE 26 8C 01 94
des_key_3 = 91 1C 80 01 01 01 01 01
ccr24_part1 = 1A 4C 59 1E 9F 62 F2 EB
ccr24_part2 = BC B5 73 C1 7D A1 F5 3E
ccr24_part3 = 88 09 FB CD 38 EB 27 9F
ccr24 --> 1A 4C 59 1E 9F 62 F2 EB BC B5 73 C1 7D A1 F5 3E 88 09 FB CD 38 EB 27 9F
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> flag
uGuess --> f l a g
byteUGuess --> f l a g
hexByteUGuess --> 66 00 6C 00 61 00 67 00 0A 00
nt_hash = 98da2ab73404f97e65d877b3253e646d
des_key_1 = 98 6D 8A 57 73 A1 13 F2
des_key_2 = 7F 32 76 0E 7A 98 94 7C
des_key_3 = 64 37 40 01 01 01 01 01
ccr24_part1 = D7 F2 66 36 63 30 CB FE
ccr24_part2 = B3 74 C0 C0 D9 96 71 E8
ccr24_part3 = 61 2B 69 DE B5 7B 71 56
ccr24 --> D7 F2 66 36 63 30 CB FE B3 74 C0 C0 D9 96 71 E8 61 2B 69 DE B5 7B 71 56
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> frog
uGuess --> f r o g
byteUGuess --> f r o g
hexByteUGuess --> 66 00 72 00 6F 00 67 00 0A 00
nt_hash = 78d1b2ee58428afdb5fff389c40b0b90
des_key_1 = 79 68 6D 5D E5 C2 0B 15
des_key_2 = FD DA 7F FE 38 4F 10 16
des_key_3 = 0B C8 01 01 01 01 01 01
ccr24_part1 = 76 1D 5C 06 E9 9D 3D 69
ccr24_part2 = C0 44 26 C6 C3 7E F9 ED
ccr24_part3 = 95 9D EB 10 8D 67 8D 6E
ccr24 --> 76 1D 5C 06 E9 9D 3D 69 C0 44 26 C6 C3 7E F9 ED 95 9D EB 10 8D 67 8D 6E
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> horse
uGuess --> h o r s e
byteUGuess --> h o r s e
hexByteUGuess --> 68 00 6F 00 72 00 73 00 65 00 0A 00
nt_hash = ee23c8c25b9443759520c49b9b6a2756
des_key_1 = EF 10 F2 19 25 DC 51 86
des_key_2 = 75 CB 49 19 49 DC 6D D5
des_key_3 = 26 AB 80 01 01 01 01 01
ccr24_part1 = 50 83 2A A8 E0 96 D5 76
ccr24_part2 = 1E 79 0E 0F 46 1C F5 D9
ccr24_part3 = 15 B1 8A EF B5 5E 5B 86
ccr24 --> 50 83 2A A8 E0 96 D5 76 1E 79 0E 0F 46 1C F5 D9 15 B1 8A EF B5 5E 5B 86
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> word
uGuess --> w o r d
byteUGuess --> w o r d
hexByteUGuess --> 77 00 6F 00 72 00 64 00 0A 00
nt_hash = 3cd0adcea3231e4d6f4e313390e25347
des_key_1 = 3D 68 2A B9 EA 19 8C 3D
des_key_2 = 4C B6 D3 C7 13 9D 43 C4
des_key_3 = 52 A2 C1 01 01 01 01 01
ccr24_part1 = DB 21 74 37 87 A2 C8 B6
ccr24_part2 = 49 E0 04 3A 77 D0 2D A5
ccr24_part3 = 22 C9 DB F7 6D E8 5A C7
ccr24 --> DB 21 74 37 87 A2 C8 B6 49 E0 04 3A 77 D0 2D A5 22 C9 DB F7 6D E8 5A C7
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> dense
uGuess --> d e n s e
byteUGuess --> d e n s e
hexByteUGuess --> 64 00 65 00 6E 00 73 00 65 00 0A 00
nt_hash = 2e46b43c23ad709512f8b1898608ef02
des_key_1 = 2F 23 AD 86 C2 1C B5 E0
des_key_2 = 94 89 BF 16 19 4C 19 10
des_key_3 = EF 80 80 01 01 01 01 01
ccr24_part1 = CB C1 1E AB DC 27 58 67
ccr24_part2 = 09 25 34 A4 83 D0 C3 68
ccr24_part3 = 56 22 E7 84 45 B2 F3 6D
ccr24 --> CB C1 1E AB DC 27 58 67 09 25 34 A4 83 D0 C3 68 56 22 E7 84 45 B2 F3 6D
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Guess ---> SecREt01
uGuess --> S e c R E t 0 1
byteUGuess --> S e c R E t 0 1
hexByteUGuess --> 53 00 65 00 63 00 52 00 45 00 74 00 30 00 31 00
nt_hash = cd06ca7c7e10c99b1d33b7485a2ed808
des_key_1 = CD 83 B3 4F C7 F1 43 92
des_key_2 = 9B 8F 4C 76 75 43 68 5D
des_key_3 = D9 04 01 01 01 01 01 01
ccr24_part1 = E7 0A E5 FE 60 61 E9 ED
ccr24_part2 = E5 BB AF 19 78 E0 C0 A6
ccr24_part3 = 12 04 60 76 E6 1F D1 AB
ccr24 --> E7 0A E5 FE 60 61 E9 ED E5 BB AF 19 78 E0 C0 A6 12 04 60 76 E6 1F D1 AB
CCR24 -----> E9 CC B4 9A 08 46 30 8B 4E 44 17 E7 CB A9 AF 4D 85 09 8B 89 4F 8A 18 D6
Failure - Dictionary exhausted...
- Password not found.

vbscript match within a match

Good day all.
I am running some Cisco show commands on a router. I am capturing the output to an array. I want to use Regex to find certain information in the output. The Regex works in the sense that it find the line containing it however there is not enough unique information I can create my regex with so I end up with more that I want. Here is the output:
ROUTERNAME#sh diag
Slot 0:
C2821 Motherboard with 2GE and integrated VPN Port adapter, 2 ports
Port adapter is analyzed
Port adapter insertion time 18w4d ago
Onboard VPN : v2.3.3
EEPROM contents at hardware discovery:
PCB Serial Number : FOC1XXXXXXXXX
Hardware Revision : 1.0
Top Assy. Part Number : 800-26921-04
Board Revision : E0
Deviation Number : 0
Fab Version : 03
RMA Test History : 00
RMA Number : 0-0-0-0
RMA History : 00
Processor type : 87
Hardware date code : 20090816
Chassis Serial Number : FTXXXXXXXXXX
Chassis MAC Address : 0023.ebf4.5480
MAC Address block size : 32
CLEI Code : COMV410ARA
Product (FRU) Number : CISCO2821
Part Number : 73-8853-05
Version Identifier : V05
EEPROM format version 4
EEPROM contents (hex):
0x00: 04 FF C1 8B 46 4F 43 31 33 33 33 31 4E 36 34 40
0x10: 03 E8 41 01 00 C0 46 03 20 00 69 29 04 42 45 30
0x20: 88 00 00 00 00 02 03 03 00 81 00 00 00 00 04 00
0x30: 09 87 83 01 32 8F C0 C2 8B 46 54 58 31 33 33 36
0x40: 41 30 4C 41 C3 06 00 23 EB F4 54 80 43 00 20 C6
0x50: 8A 43 4F 4D 56 34 31 30 41 52 41 CB 8F 43 49 53
0x60: 43 4F 32 38 32 31 20 20 20 20 20 20 82 49 22 95
0x70: 05 89 56 30 35 20 D9 02 40 C1 FF FF FF FF FF FF
AIM Module in slot: 0
Hardware Revision : 1.0
Top Assy. Part Number : 800-27059-01
Board Revision : A0
Deviation Number : 0-0
Fab Version : 02
PCB Serial Number : FOXXXXXXXXX
RMA Test History : 00
RMA Number : 0-0-0-0
RMA History : 00
Product (FRU) Number : AIM-VPN/SSL-2
Version Identifier : V01
EEPROM format version 4
EEPROM contents (hex):
0x00: 04 FF 40 04 F4 41 01 00 C0 46 03 20 00 69 B3 01
0x10: 42 41 30 80 00 00 00 00 02 02 C1 8B 46 4F 43 31
0x20: 33 33 31 36 39 59 55 03 00 81 00 00 00 00 04 00
0x30: CB 8D 41 49 4D 2D 56 50 4E 2F 53 53 4C 2D 32 89
0x40: 56 30 31 00 D9 02 40 C1 FF FF FF FF FF FF FF FF
0x50: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x60: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x70: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
What I want to capture is the Model number that is contained in the 'Product (FRU) Number:' section. In this example 'CISCO2821'. I want to output or MsgBox just the CISCO2821 although other possibilities could be 'CISCO2911/K9' or something similar.
This is the regex pattern I am using:
Product\s\(FRU\)\sNumber\s*:\s*CIS.*
Using a regex testing tool I was able to match the entire line containing what I want but I want to write only the model number.
I looked at 'ltrim' and 'rtrim' but did not think that could do it.
Any help would be greatly appreciated.
Regards.
Ok, this is in VB.NET not vbscript, but this may help get you on your way:
Dim RegexObj As New Regex("Product\s\(FRU\)\sNumber[\s\t]+:\s(CIS.+?)$", RegexOptions.IgnoreCase Or RegexOptions.Multiline)
ResultString = RegexObj.Match(SubjectString).Groups(1).Value
Invest in 2 little helper functions:
Function qq(sT) : qq = """" & sT & """" : End Function
Function newRE(sP, sF)
Set newRE = New RegExp
newRE.Pattern = sP
newRE.Global = "G" = Mid(sF, 1, 1)
newRE.IgnoreCase = "I" = Mid(sF, 2, 1)
newRE.MultiLine = "M" = Mid(sF, 3, 1)
End Function
and use
' 3 ways to skin this cat
Dim sInp : sInp = Join(Array( _
"CLEI Code: COMV410ARA" _
, "Product (FRU) Number : CISCO2821" _
, "Part Number:73-8853-05" _
), vbCrLf) ' or vbLf, vbCr
WScript.Echo sInp
' (1) just search for CIS + sequence of non-spaces - risky if e.g. CLEI Code starts with CIS
WScript.Echo 0, "=>", qq(newRE("CIS\S+", "gim").Execute(sInp)(0).Value)
' (2) use a capture/group (idea stolen from skyburner; just 'ported' to VBScript)
WScript.Echo 1, "=>", qq(newRE("\(FRU\)[^:]+:\s(\S+)", "gim").Execute(sInp)(0).Value)
WScript.Echo 2, "=>", qq(newRE("\(FRU\)[^:]+:\s(\S+)", "gim").Execute(sInp)(0).SubMatches(0))
' (3) generalize & use a Dictionary
Dim dicProps : Set dicProps = CreateObject("Scripting.Dictionary")
Dim oMT
For Each oMT in newRe("^\s*(.+?)\s*:\s*(.+?)\s*$", "GiM").Execute(sInp)
Dim oSM : Set oSM = oMT.SubMatches
dicProps(oSM(0)) = oSM(1)
Next
Dim sName
For Each sName In dicProps.Keys
WScript.Echo qq(sName), "=>", qq(dicProps(sName))
Next
to get this output:
CLEI Code: COMV410ARA
Product (FRU) Number : CISCO2821
Part Number:73-8853-05
0 => "CISCO2821"
1 => "(FRU) Number : CISCO2821"
2 => "CISCO2821"
"CLEI Code" => "COMV410ARA"
"Product (FRU) Number" => "CISCO2821"
"Part Number" => "73-8853-05"
and - I hope - some food for thought.
Important
a (plain) pattern matches/finds some part of the input
captures/groups/submatches/parentheses cut parts from this match
sometimes dealing with a generalized version of the problem gives
you more gain for less work

Writing BMP data getting garbage

I'm working on understanding and drawing my own DLL for PDF417 (2d barcodes). Anyhow, the actual drawing of the file is perfect, and in correct boundaries of 32 bits (as monochrome result). At the time of writing the data, the following is a memory dump as copied from C++ Visual Studio memory dump of the pointer to the bmp buffer. Each row is properly allocated to 36 wide before the next row.
Sorry about the wordwrap in the post, but my output was intended to be the same 36 bytes wide as the memory dump so you could better see the distortion.
The current drawing is 273 pixels wide by 12 pixels high, monochrome...
00 ab a8 61 d7 18 ed 18 f7 a3 89 1c dd 70 86 f5 f7 1a 20 91 3b c9 27 e7 67 12 1c 68 ae 3c b7 3e 02 eb 00 00
00 ab a8 61 d7 18 ed 18 f7 a3 89 1c dd 70 86 f5 f7 1a 20 91 3b c9 27 e7 67 12 1c 68 ae 3c b7 3e 02 eb 00 00
00 ab a8 61 d7 18 ed 18 f7 a3 89 1c dd 70 86 f5 f7 1a 20 91 3b c9 27 e7 67 12 1c 68 ae 3c b7 3e 02 eb 00 00
00 ab 81 4b ca 07 6b 9c 11 40 9a e6 0c 76 0a fc a3 33 70 bb 30 55 87 e9 c4 10 58 d9 ea 0d 48 3e 02 eb 00 00
00 ab 81 4b ca 07 6b 9c 11 40 9a e6 0c 76 0a fc a3 33 70 bb 30 55 87 e9 c4 10 58 d9 ea 0d 48 3e 02 eb 00 00
00 ab 81 4b ca 07 6b 9c 11 40 9a e6 0c 76 0a fc a3 33 70 bb 30 55 87 e9 c4 10 58 d9 ea 0d 48 3e 02 eb 00 00
00 ab 85 7e d0 29 e8 14 f4 0a 7a 05 3c 37 ba 86 87 04 db b6 09 dc a0 62 fc d1 31 79 bc 5c 0a 8e 02 eb 00 00
00 ab 85 7e d0 29 e8 14 f4 0a 7a 05 3c 37 ba 86 87 04 db b6 09 dc a0 62 fc d1 31 79 bc 5c 0a 8e 02 eb 00 00
00 ab 85 7e d0 29 e8 14 f4 0a 7a 05 3c 37 ba 86 87 04 db b6 09 dc a0 62 fc d1 31 79 bc 5c 0a 8e 02 eb 00 00
00 ab 85 43 c5 30 e2 26 70 4a 1a f3 e4 4d ce 2a 3f 79 cd bc e6 de 73 6f 39 b7 9c db ce 6d 5f be 02 eb 00 00
00 ab 85 43 c5 30 e2 26 70 4a 1a f3 e4 4d ce 2a 3f 79 cd bc e6 de 73 6f 39 b7 9c db ce 6d 5f be 02 eb 00 00
00 ab 85 43 c5 30 e2 26 70 4a 1a f3 e4 4d ce 2a 3f 79 cd bc e6 de 73 6f 39 b7 9c db ce 6d 5f be 02 eb 00 00
Here is the code to WRITE the file out -- verbatim immediately at the time of the memory dump from above
FILE *stream;
if( fopen_s( &stream, cSaveToFile, "w+" ) == 0 )
{
fwrite( &bmfh, 1, (UINT)sizeof(BITMAPFILEHEADER), stream );
fwrite( &bmi, 1, (UINT)sizeof(BITMAPINFO), stream );
fwrite( &RGBWhite, 1, (UINT)sizeof(RGBQUAD), stream );
fwrite( ppvBits, 1, (UINT)bmi.bmiHeader.biSizeImage, stream );
fclose( stream );
}
Here's what ACTUALLY Gets written to the file.
00 ab a8 61 d7 18 ed 18 f7 a3 89 1c dd 70 86 f5 f7 1a 20 91 3b c9 27 e7 67 12 1c 68 ae 3c b7 3e 02 eb 00 00
00 ab a8 61 d7 18 ed 18 f7 a3 89 1c dd 70 86 f5 f7 1a 20 91 3b c9 27 e7 67 12 1c 68 ae 3c b7 3e 02 eb 00 00
00 ab a8 61 d7 18 ed 18 f7 a3 89 1c dd 70 86 f5 f7 1a 20 91 3b c9 27 e7 67 12 1c 68 ae 3c b7 3e 02 eb 00 00
00 ab 81 4b ca 07 6b 9c 11 40 9a e6 0c 76 0d 0a fc a3 33 70 bb 30 55 87 e9 c4 10 58 d9 ea 0d 48 3e 02 eb 00
00 00 ab 81 4b ca 07 6b 9c 11 40 9a e6 0c 76 0d 0a fc a3 33 70 bb 30 55 87 e9 c4 10 58 d9 ea 0d 48 3e 02 eb
00 00 00 ab 81 4b ca 07 6b 9c 11 40 9a e6 0c 76 0d 0a fc a3 33 70 bb 30 55 87 e9 c4 10 58 d9 ea 0d 48 3e 02
eb 00 00 00 ab 85 7e d0 29 e8 14 f4 0d 0a 7a 05 3c 37 ba 86 87 04 db b6 09 dc a0 62 fc d1 31 79 bc 5c 0d 0a
8e 02 eb 00 00 00 ab 85 7e d0 29 e8 14 f4 0d 0a 7a 05 3c 37 ba 86 87 04 db b6 09 dc a0 62 fc d1 31 79 bc 5c
0d 0a 8e 02 eb 00 00 00 ab 85 7e d0 29 e8 14 f4 0d 0a 7a 05 3c 37 ba 86 87 04 db b6 09 dc a0 62 fc d1 31 79
bc 5c 0d 0a 8e 02 eb 00 00 00 ab 85 43 c5 30 e2 26 70 4a 1a f3 e4 4d ce 2a 3f 79 cd bc e6 de 73 6f 39 b7 9c
db ce 6d 5f be 02 eb 00 00 00 ab 85 43 c5 30 e2 26 70 4a 1a f3 e4 4d ce 2a 3f 79 cd bc e6 de 73 6f 39 b7 9c
db ce 6d 5f be 02 eb 00 00 00 ab 85 43 c5 30 e2 26 70 4a 1a f3 e4 4d ce 2a 3f 79 cd bc e6 de 73 6f 39 b7 9c
db ce 6d 5f be 02 eb 00 00
Notice the start of the distortion with the "0d" in the result from reading the file back in the 4th line, about the 15th byte over... Then, there are a few more staggered around which in total, skew the image off by 9 bytes worth...
Obviously, the drawing portion is working ok as everything remains properly aligned in memory for the 12 lines.
Shouldn't you open the file in a compound mode i.e. writable & binary as in wb+?
Notice the start of the distortion with the "0d"
That's ASCII code for Carriage Return (CR) -- added on some OSes with newline (where a newline is actually a sequence of CR/LF). This should go away once you start writing the output in binary mode.
Your code looks neat otherwise. Cheers!
Your 0x0A (\n) gets converted to DOS format 0x0D0A (\r\n), becouse you're write the file in text mode. Switch to binary mode.
I actually just did a similar thing in java (printing bmp data to a thermal receipt printer). There are a couple of things i want to share with you:
bmp image data != an image format from microsoft. the MS bitmap has about 54 bytes of header information before any image data. (i spent a day or two working on this before I realized the difference)
bmp image data reads left to right, top to bottom, with the most significant bit on the left.
make sure the barcode image has a bitdepth of 1. this means 1 bit = 1 pixel. hexidecimal "ab" is 10101011 in binary, those 8 pixels will be filled in accordingly.
if you have a barcode 36 bytes wide, the barcode resolution is 288 x 12, not 273 x 12. (36 * 8 = 288).
the image data should be 432 bytes in size (12 rows of 36 bytes).
i dont know what this means:
Anyhow, the actual drawing of the file is perfect, and in correct boundaries of 32 bits (as monochrome result).
monochrome means its either 1 color or another. the pixel (think bit) is either filled in or it isnt.
Hope this helps