Skip to content

Commit 5c0aa1b

Browse files
committed
re-invent a ByteArrayOutputStream which potentially avoids byte[] copy-ing
1 parent c48e3bd commit 5c0aa1b

File tree

5 files changed

+93
-37
lines changed

5 files changed

+93
-37
lines changed

src/main/java/org/jruby/ext/openssl/ASN1.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
package org.jruby.ext.openssl;
2929

3030
import java.io.ByteArrayInputStream;
31-
import java.io.ByteArrayOutputStream;
3231
import java.io.IOException;
3332
import java.io.InputStream;
3433
import java.io.PrintStream;
@@ -111,6 +110,7 @@
111110
import org.jruby.ext.openssl.impl.ASN1Registry;
112111

113112
import static org.jruby.ext.openssl.OpenSSL.*;
113+
import org.jruby.ext.openssl.util.ByteArrayOutputStream;
114114

115115
/**
116116
* @author <a href="mailto:[email protected]">Ola Bini</a>

src/main/java/org/jruby/ext/openssl/PEMUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
package org.jruby.ext.openssl;
2525

2626
import java.io.ByteArrayInputStream;
27-
import java.io.ByteArrayOutputStream;
2827
import java.io.IOException;
2928
import java.io.Reader;
3029
import java.io.Writer;
@@ -60,6 +59,7 @@
6059
import org.jruby.ext.openssl.impl.pem.PEMException;
6160
import org.jruby.ext.openssl.impl.pem.PEMKeyPair;
6261
import org.jruby.ext.openssl.impl.pem.PEMParser;
62+
import org.jruby.ext.openssl.util.ByteArrayOutputStream;
6363
//import org.bouncycastle.util.io.pem.PemReader;
6464

6565
import static org.jruby.ext.openssl.x509store.PEMInputOutput.getKeyFactory;

src/main/java/org/jruby/ext/openssl/StringHelper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ static RubyString newString(final Ruby runtime, final byte[] bytes) {
5656
return RubyString.newString(runtime, byteList);
5757
}
5858

59+
static RubyString newString(final Ruby runtime, final byte[] bytes, final int count) {
60+
final ByteList byteList = new ByteList(bytes, 0, count, false);
61+
return RubyString.newString(runtime, byteList);
62+
}
63+
5964
static RubyString newUTF8String(final Ruby runtime, final ByteList bytes) {
6065
ByteList byteList = new ByteList(RubyEncoding.encodeUTF8(bytes), UTF8Encoding.INSTANCE, false);
6166
return new RubyString(runtime, runtime.getString(), byteList);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2016 kares.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*/
8+
package org.jruby.ext.openssl.util;
9+
10+
/**
11+
* Allows direct buffer access for less copy-ing.
12+
*
13+
* @author kares
14+
*/
15+
public final class ByteArrayOutputStream extends java.io.ByteArrayOutputStream {
16+
17+
public ByteArrayOutputStream() {
18+
super();
19+
}
20+
21+
public ByteArrayOutputStream(int size) {
22+
super(size);
23+
}
24+
25+
public byte[] buffer() {
26+
return buf;
27+
}
28+
29+
public int size() {
30+
return count;
31+
}
32+
33+
@Override
34+
public byte[] toByteArray() {
35+
final int len = buf.length;
36+
if (count == len) return buf; // no-copying
37+
38+
final byte[] copy = new byte[count];
39+
System.arraycopy(buf, 0, copy, 0, count);
40+
return copy;
41+
}
42+
43+
}

src/main/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
import java.io.BufferedReader;
3535
import java.io.Reader;
3636
import java.io.ByteArrayInputStream;
37-
import java.io.ByteArrayOutputStream;
38-
3937
import java.math.BigInteger;
4038

4139
import java.security.GeneralSecurityException;
@@ -130,8 +128,8 @@
130128
import org.jruby.ext.openssl.impl.ASN1Registry;
131129
import org.jruby.ext.openssl.impl.CipherSpec;
132130
import org.jruby.ext.openssl.impl.PKCS10Request;
133-
134131
import org.jruby.ext.openssl.SecurityHelper;
132+
import org.jruby.ext.openssl.util.ByteArrayOutputStream;
135133

136134
/**
137135
* Helper class to read and write PEM files correctly.
@@ -846,10 +844,10 @@ private static byte[] getEncoded(X509CRL crl) throws IOException {
846844

847845
public static void writeDSAPublicKey(Writer _out, DSAPublicKey obj) throws IOException {
848846
BufferedWriter out = makeBuffered(_out);
849-
byte[] encoding = getEncoded(obj);
847+
final byte[] enc = getEncoded(obj);
850848
out.write(BEF_G + PEM_STRING_PUBLIC + AFT);
851849
out.newLine();
852-
writeEncoded(out, encoding);
850+
writeEncoded(out, enc, enc.length);
853851
out.write(BEF_E + PEM_STRING_PUBLIC + AFT);
854852
out.newLine();
855853
out.flush();
@@ -858,71 +856,71 @@ public static void writeDSAPublicKey(Writer _out, DSAPublicKey obj) throws IOExc
858856
/** writes an RSA public key encoded in an PKCS#1 RSA structure. */
859857
public static void writeRSAPublicKey(Writer _out, RSAPublicKey obj) throws IOException {
860858
BufferedWriter out = makeBuffered(_out);
861-
byte[] encoding = getEncoded(obj);
859+
final byte[] enc = getEncoded(obj);
862860
out.write(BEF_G + PEM_STRING_PUBLIC + AFT);
863861
out.newLine();
864-
writeEncoded(out, encoding);
862+
writeEncoded(out, enc, enc.length);
865863
out.write(BEF_E + PEM_STRING_PUBLIC + AFT);
866864
out.newLine();
867865
out.flush();
868866
}
869867

870868
public static void writeECPublicKey(Writer _out, ECPublicKey obj) throws IOException {
871869
BufferedWriter out = makeBuffered(_out);
872-
byte[] encoding = getEncoded(obj);
870+
final byte[] enc = getEncoded(obj);
873871
out.write(BEF_G); out.write(PEM_STRING_PUBLIC); out.write(AFT);
874872
out.newLine();
875-
writeEncoded(out, encoding);
873+
writeEncoded(out, enc, enc.length);
876874
out.write(BEF_E); out.write(PEM_STRING_PUBLIC); out.write(AFT);
877875
out.newLine();
878876
out.flush();
879877
}
880878

881879
public static void writePKCS7(Writer _out, ContentInfo obj) throws IOException {
882880
BufferedWriter out = makeBuffered(_out);
883-
byte[] encoding = getEncoded(obj);
881+
final byte[] enc = getEncoded(obj);
884882
out.write(BEF_G + PEM_STRING_PKCS7 + AFT);
885883
out.newLine();
886-
writeEncoded(out,encoding);
884+
writeEncoded(out, enc, enc.length);
887885
out.write(BEF_E + PEM_STRING_PKCS7 + AFT);
888886
out.newLine();
889887
out.flush();
890888
}
891889
public static void writePKCS7(Writer _out, CMSSignedData obj) throws IOException {
892890
BufferedWriter out = makeBuffered(_out);
893-
byte[] encoding = getEncoded(obj);
891+
final byte[] enc = getEncoded(obj);
894892
out.write(BEF_G + PEM_STRING_PKCS7 + AFT);
895893
out.newLine();
896-
writeEncoded(out,encoding);
894+
writeEncoded(out, enc, enc.length);
897895
out.write(BEF_E + PEM_STRING_PKCS7 + AFT);
898896
out.newLine();
899897
out.flush();
900898
}
901-
public static void writePKCS7(final Writer _out, final byte[] encoded) throws IOException {
899+
public static void writePKCS7(final Writer _out, final byte[] enc) throws IOException {
902900
BufferedWriter out = makeBuffered(_out);
903901
out.write(BEF_G + PEM_STRING_PKCS7 + AFT);
904902
out.newLine();
905-
writeEncoded(out,encoded);
903+
writeEncoded(out, enc, enc.length);
906904
out.write(BEF_E + PEM_STRING_PKCS7 + AFT);
907905
out.newLine();
908906
out.flush();
909907
}
910908
public static void writeX509Certificate(final Writer _out, final X509Certificate cert) throws IOException {
911909
BufferedWriter out = makeBuffered(_out);
912-
byte[] encoding = getEncoded(cert);
910+
final byte[] enc = getEncoded(cert);
913911
out.write(BEF_G + PEM_STRING_X509 + AFT);
914912
out.newLine();
915-
writeEncoded(out, encoding);
913+
writeEncoded(out, enc, enc.length);
916914
out.write(BEF_E + PEM_STRING_X509 + AFT);
917915
out.newLine();
918916
out.flush();
919917
}
920918
public static void writeX509Aux(final Writer _out, final X509AuxCertificate cert) throws IOException {
921919
BufferedWriter out = makeBuffered(_out);
922-
byte[] encoding;
920+
final byte[] encoding; final int encLen;
923921
try {
924922
if ( cert.aux == null ) {
925-
encoding = cert.getEncoded();
923+
encoding = cert.getEncoded(); encLen = encoding.length;
926924
}
927925
else {
928926
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -958,15 +956,15 @@ public static void writeX509Aux(final Writer _out, final X509AuxCertificate cert
958956
}
959957
enc = new DLSequence(a1).getEncoded();
960958
baos.write(enc, 0, enc.length);
961-
encoding = baos.toByteArray();
959+
encoding = baos.buffer(); encLen = baos.size();
962960
}
963961
}
964962
catch (CertificateEncodingException e) {
965963
throw new IOException("problem with encoding object in write_X509_AUX", e);
966964
}
967965
out.write(BEF_G + PEM_STRING_X509_TRUSTED + AFT);
968966
out.newLine();
969-
writeEncoded(out,encoding);
967+
writeEncoded(out, encoding, encLen);
970968
out.write(BEF_E + PEM_STRING_X509_TRUSTED + AFT);
971969
out.newLine();
972970
out.flush();
@@ -976,7 +974,7 @@ public static void writeX509CRL(Writer _out, X509CRL obj) throws IOException {
976974
byte[] encoding = getEncoded(obj);
977975
out.write(BEF_G + PEM_STRING_X509_CRL + AFT);
978976
out.newLine();
979-
writeEncoded(out, encoding);
977+
writeEncoded(out, encoding, encoding.length);
980978
out.write(BEF_E + PEM_STRING_X509_CRL + AFT);
981979
out.newLine();
982980
out.flush();
@@ -986,7 +984,7 @@ public static void writeX509Request(Writer _out, PKCS10Request obj) throws IOExc
986984
byte[] encoding = getEncoded(obj.toASN1Structure());
987985
out.write(BEF_G + PEM_STRING_X509_REQ + AFT);
988986
out.newLine();
989-
writeEncoded(out,encoding);
987+
writeEncoded(out, encoding, encoding.length);
990988
out.write(BEF_E + PEM_STRING_X509_REQ + AFT);
991989
out.newLine();
992990
out.flush();
@@ -1012,12 +1010,11 @@ public static void writeDSAPrivateKey(Writer _out, DSAPrivateKey obj, CipherSpec
10121010
v.add(new ASN1Integer(x));
10131011

10141012
aOut.writeObject(new DLSequence(v));
1015-
byte[] encoding = bOut.toByteArray();
10161013

10171014
if (cipher != null && passwd != null) {
1018-
writePemEncrypted(out, PEM_STRING_DSA, encoding, cipher, passwd);
1015+
writePemEncrypted(out, PEM_STRING_DSA, bOut.buffer(), bOut.size(), cipher, passwd);
10191016
} else {
1020-
writePemPlain(out, PEM_STRING_DSA, encoding);
1017+
writePemPlain(out, PEM_STRING_DSA, bOut.buffer(), bOut.size());
10211018
}
10221019
}
10231020

@@ -1060,9 +1057,14 @@ public static void writeECParameters(Writer _out, ASN1ObjectIdentifier obj, Ciph
10601057

10611058
private static void writePemPlain(final BufferedWriter out,
10621059
final String PEM_ID, final byte[] encoding) throws IOException {
1060+
writePemPlain(out, PEM_ID, encoding, encoding.length);
1061+
}
1062+
1063+
private static void writePemPlain(final BufferedWriter out,
1064+
final String PEM_ID, final byte[] encoding, final int encLen) throws IOException {
10631065
out.write(BEF_G); out.write(PEM_ID); out.write(AFT);
10641066
out.newLine();
1065-
writeEncoded(out, encoding);
1067+
writeEncoded(out, encoding, encLen);
10661068
out.write(BEF_E); out.write(PEM_ID); out.write(AFT);
10671069
out.newLine();
10681070
out.flush();
@@ -1071,6 +1073,12 @@ private static void writePemPlain(final BufferedWriter out,
10711073
private static void writePemEncrypted(final BufferedWriter out,
10721074
final String PEM_ID, final byte[] encoding,
10731075
final CipherSpec cipherSpec, final char[] passwd) throws IOException {
1076+
writePemEncrypted(out, PEM_ID, encoding, encoding.length, cipherSpec, passwd);
1077+
}
1078+
1079+
private static void writePemEncrypted(final BufferedWriter out,
1080+
final String PEM_ID, final byte[] encoding, final int encCount,
1081+
final CipherSpec cipherSpec, final char[] passwd) throws IOException {
10741082

10751083
final Cipher cipher = cipherSpec.getCipher();
10761084
final byte[] iv = new byte[cipher.getBlockSize()];
@@ -1085,7 +1093,7 @@ private static void writePemEncrypted(final BufferedWriter out,
10851093
final byte[] encData;
10861094
try {
10871095
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
1088-
encData = cipher.doFinal(encoding);
1096+
encData = cipher.doFinal(encoding, 0, encCount);
10891097
}
10901098
catch (InvalidKeyException e) {
10911099
final String msg = e.getMessage();
@@ -1105,7 +1113,7 @@ private static void writePemEncrypted(final BufferedWriter out,
11051113
writeHexEncoded(out, iv);
11061114
out.newLine();
11071115
out.newLine();
1108-
writeEncoded(out, encData);
1116+
writeEncoded(out, encData, encData.length);
11091117
out.write(BEF_E); out.write(PEM_ID); out.write(AFT);
11101118
out.flush();
11111119
}
@@ -1141,11 +1149,10 @@ public static void writeDHParameters(Writer _out, DHParameterSpec params) throws
11411149
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
11421150

11431151
aOut.writeObject(new DLSequence(v));
1144-
byte[] encoding = bOut.toByteArray();
11451152

11461153
out.write(BEF_G); out.write(PEM_STRING_DHPARAMS); out.write(AFT);
11471154
out.newLine();
1148-
writeEncoded(out, encoding);
1155+
writeEncoded(out, bOut.buffer(), bOut.size());
11491156
out.write(BEF_E); out.write(PEM_STRING_DHPARAMS); out.write(AFT);
11501157
out.newLine();
11511158
out.flush();
@@ -1483,17 +1490,18 @@ private static void writeHexEncoded(BufferedWriter out, byte[] bytes) throws IOE
14831490
}
14841491
}
14851492

1486-
private static void writeEncoded(BufferedWriter out, byte[] bytes) throws IOException {
1487-
char[] buf = new char[64];
1488-
bytes = Base64.encode(bytes);
1493+
private static void writeEncoded(BufferedWriter out,
1494+
byte[] bytes, final int bytesLen) throws IOException {
1495+
final char[] buf = new char[64];
1496+
bytes = Base64.encode(bytes, 0 ,bytesLen);
14891497
for (int i = 0; i < bytes.length; i += buf.length) {
14901498
int index = 0;
14911499

14921500
while (index != buf.length) {
14931501
if ((i + index) >= bytes.length) {
14941502
break;
14951503
}
1496-
buf[index] = (char)bytes[i + index];
1504+
buf[index] = (char) bytes[i + index];
14971505
index++;
14981506
}
14991507
out.write(buf, 0, index);

0 commit comments

Comments
 (0)