List of usage examples for io.netty.buffer ByteBuf writerIndex
public abstract int writerIndex();
From source file:divconq.test.pgp.PGPWriter2.java
License:Open Source License
@SuppressWarnings("resource") public void test2(String srcpath, String destpath, String keyring) throws Exception { Path src = Paths.get(srcpath); // file data byte[] fileData = Files.readAllBytes(src); // dest//from w w w . java2s .com OutputStream dest = new BufferedOutputStream(new FileOutputStream(destpath)); // encryption key PGPPublicKey pubKey = null; InputStream keyIn = new BufferedInputStream(new FileInputStream(keyring)); PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection( org.bouncycastle.openpgp.PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator()); // // we just loop through the collection till we find a key suitable for encryption, in the real // world you would probably want to be a bit smarter about this. // @SuppressWarnings("rawtypes") Iterator keyRingIter = pgpPub.getKeyRings(); while (keyRingIter.hasNext() && (pubKey == null)) { PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next(); @SuppressWarnings("rawtypes") Iterator keyIter = keyRing.getPublicKeys(); while (keyIter.hasNext() && (pubKey == null)) { PGPPublicKey key = (PGPPublicKey) keyIter.next(); if (key.isEncryptionKey()) pubKey = key; } } if (pubKey == null) throw new IllegalArgumentException("Can't find encryption key in key ring."); String fileName = src.getFileName().toString(); byte[] encName = Utf8Encoder.encode(fileName); long modificationTime = System.currentTimeMillis(); SecureRandom rand = new SecureRandom(); int algorithm = PGPEncryptedData.AES_256; Cipher cipher = null; ByteBuf leadingbuf = Hub.instance.getBufferAllocator().heapBuffer(1024 * 1024); // 1 mb ByteBuf encbuf = Hub.instance.getBufferAllocator().heapBuffer(1024 * 1024); // 1 mb // ******************************************************************* // public key packet // ******************************************************************* PGPKeyEncryptionMethodGenerator method = new JcePublicKeyKeyEncryptionMethodGenerator(pubKey); byte[] key = org.bouncycastle.openpgp.PGPUtil.makeRandomKey(algorithm, rand); byte[] sessionInfo = new byte[key.length + 3]; // add algorithm sessionInfo[0] = (byte) algorithm; // add key System.arraycopy(key, 0, sessionInfo, 1, key.length); // add checksum int check = 0; for (int i = 1; i != sessionInfo.length - 2; i++) check += sessionInfo[i] & 0xff; sessionInfo[sessionInfo.length - 2] = (byte) (check >> 8); sessionInfo[sessionInfo.length - 1] = (byte) (check); ContainedPacket packet1 = method.generate(algorithm, sessionInfo); byte[] encoded1 = packet1.getEncoded(); leadingbuf.writeBytes(encoded1); // ******************************************************************* // encrypt packet, add IV to encryption though // ******************************************************************* leadingbuf.writeByte(0xC0 | PacketTags.SYM_ENC_INTEGRITY_PRO); this.writePacketLength(leadingbuf, 0); // 0 = we don't know leadingbuf.writeByte(1); // version number String cName = PGPUtil.getSymmetricCipherName(algorithm) + "/CFB/NoPadding"; DefaultJcaJceHelper helper = new DefaultJcaJceHelper(); cipher = helper.createCipher(cName); byte[] iv = new byte[cipher.getBlockSize()]; cipher.init(Cipher.ENCRYPT_MODE, PGPUtil.makeSymmetricKey(algorithm, key), new IvParameterSpec(iv)); // ******************** start encryption ********************** // --- encrypt checksum for encrypt packet, part of the encrypted output --- byte[] inLineIv = new byte[cipher.getBlockSize() + 2]; rand.nextBytes(inLineIv); inLineIv[inLineIv.length - 1] = inLineIv[inLineIv.length - 3]; inLineIv[inLineIv.length - 2] = inLineIv[inLineIv.length - 4]; encbuf.writeBytes(inLineIv); System.out.println("bytes written a: " + encbuf.readableBytes()); // --- data packet --- int chunkpos = 0; int headerlen = 1 // format + 1 // name length + encName.length // file name + 4; // time encbuf.writeByte(0xC0 | PacketTags.LITERAL_DATA); int packetsize = 512 - headerlen; if (fileData.length - chunkpos < packetsize) { packetsize = fileData.length - chunkpos; this.writePacketLength(encbuf, headerlen + packetsize); } else { encbuf.writeByte(0xE9); // 512 packet length } System.out.println("bytes written b: " + encbuf.readableBytes()); encbuf.writeByte(PGPLiteralData.BINARY); // data format encbuf.writeByte((byte) encName.length); // file name encbuf.writeBytes(encName); encbuf.writeInt((int) (modificationTime / 1000)); // mod time System.out.println("bytes written c: " + encbuf.readableBytes()); encbuf.writeBytes(fileData, chunkpos, packetsize); System.out.println("bytes written d: " + encbuf.readableBytes()); chunkpos += packetsize; // write one or more literal packets while (chunkpos < fileData.length) { packetsize = 512; // check if this is the final packet if (fileData.length - chunkpos <= packetsize) { packetsize = fileData.length - chunkpos; this.writePacketLength(encbuf, packetsize); } else { encbuf.writeByte(0xE9); // full 512 packet length } encbuf.writeBytes(fileData, chunkpos, packetsize); chunkpos += packetsize; } // protection packet encbuf.writeByte(0xC0 | PacketTags.MOD_DETECTION_CODE); encbuf.writeByte(20); // packet length MessageDigest md = MessageDigest.getInstance("SHA-1"); md.update(encbuf.array(), encbuf.arrayOffset(), encbuf.writerIndex()); byte[] rv = md.digest(); encbuf.writeBytes(rv); System.out.println("Pre-Encrypted Hex"); this.hexDump(encbuf.array(), encbuf.arrayOffset(), encbuf.writerIndex()); System.out.println(); System.out.println(); // ***** encryption data ready ********* byte[] encdata = cipher.doFinal(encbuf.array(), encbuf.arrayOffset(), encbuf.writerIndex()); // add encrypted data to main buffer leadingbuf.writeBytes(encdata); System.out.println("Final Hex"); this.hexDump(leadingbuf.array(), leadingbuf.arrayOffset(), leadingbuf.writerIndex()); System.out.println(); System.out.println(); // write to file dest.write(leadingbuf.array(), leadingbuf.arrayOffset(), leadingbuf.writerIndex()); dest.flush(); dest.close(); }
From source file:divconq.test.pgp.PGPWriter2.java
License:Open Source License
@SuppressWarnings("resource") public void test1(String srcpath, String destpath, String keyring) throws Exception { Path src = Paths.get(srcpath); // file data byte[] story = Files.readAllBytes(src); // dest/*ww w. j av a 2 s .c o m*/ OutputStream dest = new BufferedOutputStream(new FileOutputStream(destpath)); // encryption key PGPPublicKey pubKey = null; InputStream keyIn = new BufferedInputStream(new FileInputStream(keyring)); PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection( org.bouncycastle.openpgp.PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator()); // // we just loop through the collection till we find a key suitable for encryption, in the real // world you would probably want to be a bit smarter about this. // @SuppressWarnings("rawtypes") Iterator keyRingIter = pgpPub.getKeyRings(); while (keyRingIter.hasNext() && (pubKey == null)) { PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next(); @SuppressWarnings("rawtypes") Iterator keyIter = keyRing.getPublicKeys(); while (keyIter.hasNext() && (pubKey == null)) { PGPPublicKey key = (PGPPublicKey) keyIter.next(); if (key.isEncryptionKey()) pubKey = key; } } if (pubKey == null) throw new IllegalArgumentException("Can't find encryption key in key ring."); String fileName = src.getFileName().toString(); byte[] encName = Utf8Encoder.encode(fileName); long modificationTime = System.currentTimeMillis(); SecureRandom rand = new SecureRandom(); int algorithm = PGPEncryptedData.AES_256; Cipher cipher = null; ByteBuf leadingbuf = Hub.instance.getBufferAllocator().heapBuffer(1024 * 1024); // 1 mb ByteBuf encbuf = Hub.instance.getBufferAllocator().heapBuffer(1024 * 1024); // 1 mb // ******************************************************************* // public key packet // ******************************************************************* PGPKeyEncryptionMethodGenerator method = new JcePublicKeyKeyEncryptionMethodGenerator(pubKey); byte[] key = org.bouncycastle.openpgp.PGPUtil.makeRandomKey(algorithm, rand); byte[] sessionInfo = new byte[key.length + 3]; // add algorithm sessionInfo[0] = (byte) algorithm; // add key System.arraycopy(key, 0, sessionInfo, 1, key.length); // add checksum int check = 0; for (int i = 1; i != sessionInfo.length - 2; i++) check += sessionInfo[i] & 0xff; sessionInfo[sessionInfo.length - 2] = (byte) (check >> 8); sessionInfo[sessionInfo.length - 1] = (byte) (check); ContainedPacket packet1 = method.generate(algorithm, sessionInfo); byte[] encoded1 = packet1.getEncoded(); leadingbuf.writeBytes(encoded1); // ******************************************************************* // encrypt packet, add IV to // ******************************************************************* String cName = PGPUtil.getSymmetricCipherName(algorithm) + "/CFB/NoPadding"; DefaultJcaJceHelper helper = new DefaultJcaJceHelper(); cipher = helper.createCipher(cName); byte[] iv = new byte[cipher.getBlockSize()]; cipher.init(Cipher.ENCRYPT_MODE, PGPUtil.makeSymmetricKey(algorithm, key), new IvParameterSpec(iv)); // ******************** start encryption ********************** // --- encrypt checksum for encrypt packet, part of the encrypted output --- byte[] inLineIv = new byte[cipher.getBlockSize() + 2]; rand.nextBytes(inLineIv); inLineIv[inLineIv.length - 1] = inLineIv[inLineIv.length - 3]; inLineIv[inLineIv.length - 2] = inLineIv[inLineIv.length - 4]; encbuf.writeBytes(inLineIv); // --- data packet --- encbuf.writeByte(0xC0 | PacketTags.LITERAL_DATA); this.writePacketLength(encbuf, 1 // format + 1 // name length + encName.length // file name + 4 // time + story.length // data ); encbuf.writeByte(PGPLiteralData.BINARY); encbuf.writeByte((byte) encName.length); encbuf.writeBytes(encName); encbuf.writeInt((int) (modificationTime / 1000)); encbuf.writeBytes(story); // protection packet encbuf.writeByte(0xC0 | PacketTags.MOD_DETECTION_CODE); encbuf.writeByte(20); // packet length MessageDigest md = MessageDigest.getInstance("SHA-1"); md.update(encbuf.array(), encbuf.arrayOffset(), encbuf.writerIndex()); byte[] rv = md.digest(); encbuf.writeBytes(rv); System.out.println("Encrypted Hex"); this.hexDump(encbuf.array(), encbuf.arrayOffset(), encbuf.writerIndex()); System.out.println(); System.out.println(); // ***** encryption data ready ********* byte[] encdata = cipher.doFinal(encbuf.array(), encbuf.arrayOffset(), encbuf.writerIndex()); leadingbuf.writeByte(0xC0 | PacketTags.SYM_ENC_INTEGRITY_PRO); /* this.writePacketLength(leadingbuf, 1 // version + encdata.length // encrypted data ); */ this.writePacketLength(leadingbuf, 0); // 0 = we don't know leadingbuf.writeByte(1); // version number // add encrypted data to main buffer leadingbuf.writeBytes(encdata); System.out.println("Final Hex"); this.hexDump(leadingbuf.array(), leadingbuf.arrayOffset(), leadingbuf.writerIndex()); System.out.println(); System.out.println(); // write to file dest.write(leadingbuf.array(), leadingbuf.arrayOffset(), leadingbuf.writerIndex()); dest.flush(); dest.close(); }
From source file:divconq.web.http.ServerHandler.java
License:Open Source License
public void handleHttpRequest(ChannelHandlerContext ctx, HttpObject httpobj) throws Exception { if (httpobj instanceof HttpContent) { this.context.offerContent((HttpContent) httpobj); return;/*from w w w . j ava2 s. c o m*/ } if (!(httpobj instanceof HttpRequest)) { this.context.sendRequestBad(); return; } HttpRequest httpreq = (HttpRequest) httpobj; this.context.load(ctx, httpreq); // Handle a bad request. if (!httpreq.getDecoderResult().isSuccess()) { this.context.sendRequestBad(); return; } Request req = this.context.getRequest(); Response resp = this.context.getResponse(); // to avoid lots of unused sessions if (req.pathEquals("/favicon.ico") || req.pathEquals("/robots.txt")) { this.context.sendNotFound(); return; } // make sure we don't have a leftover task context OperationContext.clear(); String origin = "http:" + NetUtil.formatIpAddress((InetSocketAddress) ctx.channel().remoteAddress()); // TODO use X-Forwarded-For if available, maybe a plug in approach to getting client's IP? DomainInfo dinfo = this.context.getSiteman().resolveDomainInfo(req.getHeader("Host")); if (dinfo == null) { this.context.sendForbidden(); return; } WebDomain wdomain = this.context.getSiteman().getDomain(dinfo.getId()); // check into url re-routing String reroute = wdomain.route(req, (SslHandler) ctx.channel().pipeline().get("ssl")); if (StringUtil.isNotEmpty(reroute)) { this.context.getResponse().setStatus(HttpResponseStatus.FOUND); this.context.getResponse().setHeader("Location", reroute); this.context.send(); return; } Cookie sesscookie = req.getCookie("SessionId"); Session sess = null; if (sesscookie != null) { String v = sesscookie.getValue(); String sessionid = v.substring(0, v.lastIndexOf('_')); String accesscode = v.substring(v.lastIndexOf('_') + 1); sess = Hub.instance.getSessions().lookupAuth(sessionid, accesscode); } if (sess == null) { sess = Hub.instance.getSessions().create(origin, dinfo.getId()); Logger.info("Started new session: " + sess.getId() + " on " + req.getPath() + " for " + origin); // TODO if ssl set client key on user context //req.getSecuritySession().getPeerCertificates(); sess.setAdatper(new ISessionAdapter() { protected volatile ListStruct msgs = new ListStruct(); @Override public void stop() { ServerHandler.this.context.close(); } @Override public ListStruct popMessages() { ListStruct ret = this.msgs; this.msgs = new ListStruct(); return ret; } @Override public void deliver(Message msg) { // keep no more than 100 messages - this is not a "reliable" approach, just basic comm help while (this.msgs.getSize() > 99) this.msgs.removeItem(0); this.msgs.addItem(msg); } }); Cookie sk = new DefaultCookie("SessionId", sess.getId() + "_" + sess.getKey()); sk.setPath("/"); sk.setHttpOnly(true); resp.setCookie(sk); } this.context.setSession(sess); sess.touch(); OperationContext tc = sess.setContext(origin); tc.info("Web request for host: " + req.getHeader("Host") + " url: " + req.getPath() + " by: " + origin + " session: " + sess.getId()); /* System.out.println("sess proto: " + ((SslHandler)ctx.channel().pipeline().get("ssl")).engine().getSession().getProtocol()); System.out.println("sess suite: " + ((SslHandler)ctx.channel().pipeline().get("ssl")).engine().getSession().getCipherSuite()); */ try { if (req.pathEquals(ServerHandler.BUS_PATH)) { // Allow only GET methods. if (req.getMethod() != HttpMethod.GET) { this.context.sendForbidden(); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( ServerHandler.getWebSocketLocation( "True".equals(this.context.getConfig().getAttribute("Secure")), httpreq), null, false); this.handshaker = wsFactory.newHandshaker(httpreq); if (this.handshaker == null) WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); else { DefaultFullHttpRequest freq = new DefaultFullHttpRequest(httpreq.getProtocolVersion(), httpreq.getMethod(), httpreq.getUri()); freq.headers().add(httpreq.headers()); this.handshaker.handshake(ctx.channel(), freq); return; } this.context.sendForbidden(); return; } // "upload" is it's own built-in extension. if ((req.getPath().getNameCount() == 3) && req.getPath().getName(0).equals(ServerHandler.UPLOAD_PATH)) { if (!Hub.instance.isRunning()) { // only allow uploads when running this.context.sendRequestBad(); return; } // currently only supporting POST/PUT of pure binary - though support for form uploads can be restored, see below // we cannot rely on content type being meaningful //if (!"application/octet-stream".equals(req.getContentType().getPrimary())) { // this.context.sendRequestBad(); // return; //} // TODO add CORS support if needed if ((req.getMethod() != HttpMethod.PUT) && (req.getMethod() != HttpMethod.POST)) { this.context.sendRequestBad(); return; } final String cid = req.getPath().getName(1); final String op = req.getPath().getName(2); final DataStreamChannel dsc = sess.getChannel(cid); if (dsc == null) { this.context.sendRequestBad(); return; } dsc.setDriver(new IStreamDriver() { @Override public void cancel() { Logger.error("Transfer canceled on channel: " + cid); dsc.complete(); ServerHandler.this.context.sendRequestBad(); // TODO headers? } @Override public void nextChunk() { Logger.debug("Continue on channel: " + cid); ServerHandler.this.context.sendRequestOk(); } @Override public void message(StreamMessage msg) { if (msg.isFinal()) { Logger.debug("Final on channel: " + cid); dsc.complete(); ServerHandler.this.context.sendRequestOk(); } } }); //if (req.getMethod() == HttpMethod.PUT) { this.context.setDecoder(new IContentDecoder() { protected boolean completed = false; protected int seq = 0; @Override public void release() { // trust that http connection is closing or what ever needs to happen, we just need to deal with datastream Logger.debug("Releasing data stream"); // if not done with request then something went wrong, kill data channel if (!this.completed) dsc.abort(); } @Override public void offer(HttpContent chunk) { boolean finalchunk = (chunk instanceof LastHttpContent); //System.out.println("Chunk: " + finalchunk); ByteBuf buffer = chunk.content(); if (!dsc.isClosed()) { int size = buffer.readableBytes(); //System.out.println("Chunk size: " + size); dsc.touch(); // TODO try to set progress on dsc // TODO set hint in netty as to where this buffer was handled and sent if (size > 0) { buffer.retain(); // we will be using a reference up during send StreamMessage b = new StreamMessage("Block", buffer); b.setField("Sequence", this.seq); //System.out.println("Buffer ref cnt a: " + buffer.refCnt()); OperationResult or = dsc.send(b); //System.out.println("Buffer ref cnt b: " + buffer.refCnt()); // indicate we have read the buffer? buffer.readerIndex(buffer.writerIndex()); if (or.hasErrors()) { dsc.close(); return; } this.seq++; } // if last buffer of last block then mark the upload as completed if (finalchunk) { if ("Final".equals(op)) dsc.send(MessageUtil.streamFinal()); else dsc.getDriver().nextChunk(); } } // means this block is completed, not necessarily entire file uploaded if (finalchunk) this.completed = true; } }); //return; //} /* old approach that supported multipart posts TODO review/remove if (req.getMethod() == HttpMethod.POST) { StreamingDataFactory sdf = new StreamingDataFactory(dsc, op); // TODO consider supporting non-multipart? final HttpPostMultipartRequestDecoder prd = new HttpPostMultipartRequestDecoder(sdf, httpreq); this.context.setDecoder(new IContentDecoder() { @Override public void release() { // trust that http connection is closing or what ever needs to happen, we just need to deal with datastream // if not done with request then something went wrong, kill data channel if ((prd.getStatus() != MultiPartStatus.EPILOGUE) && (prd.getStatus() != MultiPartStatus.PREEPILOGUE)) dsc.kill(); } @Override public void offer(HttpContent chunk) { //the only thing we care about is the file, the file will stream to dsc - the rest can disappear prd.offer(chunk); } }); return; } */ //this.context.sendRequestBad(); return; } // "download" is it's own built-in extension. if ((req.getPath().getNameCount() == 2) && req.getPath().getName(0).equals(ServerHandler.DOWNLOAD_PATH)) { if (!Hub.instance.isRunning()) { // only allow downloads when running this.context.sendRequestBad(); return; } if (req.getMethod() != HttpMethod.GET) { this.context.sendRequestBad(); return; } String cid = req.getPath().getName(1); final DataStreamChannel dsc = sess.getChannel(cid); if (dsc == null) { this.context.sendRequestBad(); return; } dsc.setDriver(new IStreamDriver() { //protected long amt = 0; protected long seq = 0; @Override public void cancel() { dsc.complete(); ServerHandler.this.context.close(); } @Override public void nextChunk() { // meaningless in download } @Override public void message(StreamMessage msg) { int seqnum = (int) msg.getFieldAsInteger("Sequence", 0); if (seqnum != this.seq) { this.error(1, "Bad sequence number: " + seqnum); return; } if (msg.hasData()) { //this.amt += msg.getData().readableBytes(); HttpContent b = new DefaultHttpContent(Unpooled.copiedBuffer(msg.getData())); // TODO not copied ServerHandler.this.context.sendDownload(b); } this.seq++; // TODO update progress if (msg.isFinal()) { ServerHandler.this.context.sendDownload(new DefaultLastHttpContent()); ServerHandler.this.context.close(); dsc.complete(); } } public void error(int code, String msg) { dsc.send(MessageUtil.streamError(code, msg)); ServerHandler.this.context.close(); } }); // for some reason HyperSession is sending content. this.context.setDecoder(new IContentDecoder() { @Override public void release() { } @Override public void offer(HttpContent chunk) { if (!(chunk instanceof LastHttpContent)) Logger.error("Unexplained and unwanted content during download: " + chunk); } }); // tell the client that chunked content is coming this.context.sendDownloadHeaders(dsc.getPath() != null ? dsc.getPath().getFileName() : null, dsc.getMime()); // get the data flowing dsc.send(new StreamMessage("Start")); return; } if ((req.getPath().getNameCount() == 1) && req.getPath().getName(0).equals(ServerHandler.STATUS_PATH)) { if (Hub.instance.getState() == HubState.Running) this.context.sendRequestOk(); else this.context.sendRequestBad(); return; } // "rpc" is it's own built-in extension. all requests to rpc are routed through // DivConq bus, if the request is valid if (req.pathEquals(ServerHandler.RPC_PATH)) { if (req.getMethod() != HttpMethod.POST) { this.context.sendRequestBad(); return; } //System.out.println("looks like we have a rpc message"); // max 4MB of json? -- TODO is that max chunk size or max total? we don't need 4MB chunk... this.context.setDecoder(new HttpBodyRequestDecoder(4096 * 1024, new RpcHandler(this.context))); return; } // otherwise we need to figure out which extension is being called // "local" is also used to mean default extension String ext = req.pathEquals("/") ? "local" : req.getPath().getName(0); IWebExtension ex = "local".equals(ext) ? this.context.getSiteman().getDefaultExtension() : this.context.getSiteman().getExtension(ext); // still cannot figure it out, use default if (ex == null) ex = this.context.getSiteman().getDefaultExtension(); // then have extension handle it if (ex != null) { //OperationResult res = new OperationResult(); OperationResult res = ex.handle(sess, this.context); //resp.addBody("Hello"); //this.context.send(); // no errors starting page processing, return if (!res.hasErrors()) return; resp.setHeader("X-dcResultCode", res.getCode() + ""); resp.setHeader("X-dcResultMesage", res.getMessage()); this.context.sendNotFound(); return; } } catch (Exception x) { this.context.sendInternalError(); return; } this.context.sendNotFound(); }
From source file:dorkbox.network.connection.KryoExtra.java
License:Apache License
/** * This is NOT ENCRYPTED (and is only done on the loopback connection!) *//*from w w w. ja v a2s .co m*/ public synchronized void writeCompressed(final Connection_ connection, final ByteBuf buffer, final Object message) throws IOException { // required by RMI and some serializers to determine which connection wrote (or has info about) this object this.rmiSupport = connection.rmiSupport(); ByteBuf objectOutputBuffer = this.tempBuffer; objectOutputBuffer.clear(); // always have to reset everything // write the object to a TEMP buffer! this will be compressed writer.setBuffer(objectOutputBuffer); writeClassAndObject(writer, message); // save off how much data the object took + magic byte int length = objectOutputBuffer.writerIndex(); // NOTE: compression and encryption MUST work with byte[] because they use JNI! // Realistically, it is impossible to get the backing arrays out of a Heap Buffer once they are resized and begin to use // sliced. It's lame that there is a "double copy" of bytes here, but I don't know how to avoid it... // see: https://stackoverflow.com/questions/19296386/netty-java-getting-data-from-bytebuf byte[] inputArray; int inputOffset; // Even if a ByteBuf has a backing array (i.e. buf.hasArray() returns true), the using it isn't always possible because // the buffer might be a slice of other buffer or a pooled buffer: //noinspection Duplicates if (objectOutputBuffer.hasArray() && objectOutputBuffer.array()[0] == objectOutputBuffer.getByte(0) && objectOutputBuffer.array().length == objectOutputBuffer.capacity()) { // we can use it... inputArray = objectOutputBuffer.array(); inputArrayLength = -1; // this is so we don't REUSE this array accidentally! inputOffset = objectOutputBuffer.arrayOffset(); } else { // we can NOT use it. if (length > inputArrayLength) { inputArrayLength = length; inputArray = new byte[length]; this.inputArray = inputArray; } else { inputArray = this.inputArray; } objectOutputBuffer.getBytes(objectOutputBuffer.readerIndex(), inputArray, 0, length); inputOffset = 0; } ////////// compressing data // we ALWAYS compress our data stream -- because of how AES-GCM pads data out, the small input (that would result in a larger // output), will be negated by the increase in size by the encryption byte[] compressOutput = this.compressOutput; int maxLengthLengthOffset = 4; // length is never negative, so 4 is OK (5 means it's negative) int maxCompressedLength = compressor.maxCompressedLength(length); // add 4 so there is room to write the compressed size to the buffer int maxCompressedLengthWithOffset = maxCompressedLength + maxLengthLengthOffset; // lazy initialize the compression output buffer if (maxCompressedLengthWithOffset > compressOutputLength) { compressOutputLength = maxCompressedLengthWithOffset; compressOutput = new byte[maxCompressedLengthWithOffset]; this.compressOutput = compressOutput; } // LZ4 compress. output offset max 4 bytes to leave room for length of tempOutput data int compressedLength = compressor.compress(inputArray, inputOffset, length, compressOutput, maxLengthLengthOffset, maxCompressedLength); // bytes can now be written to, because our compressed data is stored in a temp array. final int lengthLength = OptimizeUtilsByteArray.intLength(length, true); // correct input. compression output is now buffer input inputArray = compressOutput; inputOffset = maxLengthLengthOffset - lengthLength; // now write the ORIGINAL (uncompressed) length to the front of the byte array (this is NOT THE BUFFER!). This is so we can use the FAST decompress version OptimizeUtilsByteArray.writeInt(inputArray, length, true, inputOffset); // have to copy over the orig data, because we used the temp buffer. Also have to account for the length of the uncompressed size buffer.writeBytes(inputArray, inputOffset, compressedLength + lengthLength); }
From source file:dorkbox.network.connection.KryoExtra.java
License:Apache License
public synchronized void writeCrypto(final Connection_ connection, final ByteBuf buffer, final Object message) throws IOException { // required by RMI and some serializers to determine which connection wrote (or has info about) this object this.rmiSupport = connection.rmiSupport(); ByteBuf objectOutputBuffer = this.tempBuffer; objectOutputBuffer.clear(); // always have to reset everything // write the object to a TEMP buffer! this will be compressed writer.setBuffer(objectOutputBuffer); writeClassAndObject(writer, message); // save off how much data the object took int length = objectOutputBuffer.writerIndex(); // NOTE: compression and encryption MUST work with byte[] because they use JNI! // Realistically, it is impossible to get the backing arrays out of a Heap Buffer once they are resized and begin to use // sliced. It's lame that there is a "double copy" of bytes here, but I don't know how to avoid it... // see: https://stackoverflow.com/questions/19296386/netty-java-getting-data-from-bytebuf byte[] inputArray; int inputOffset; // Even if a ByteBuf has a backing array (i.e. buf.hasArray() returns true), the using it isn't always possible because // the buffer might be a slice of other buffer or a pooled buffer: //noinspection Duplicates if (objectOutputBuffer.hasArray() && objectOutputBuffer.array()[0] == objectOutputBuffer.getByte(0) && objectOutputBuffer.array().length == objectOutputBuffer.capacity()) { // we can use it... inputArray = objectOutputBuffer.array(); inputArrayLength = -1; // this is so we don't REUSE this array accidentally! inputOffset = objectOutputBuffer.arrayOffset(); } else {//from w ww .j a v a 2s .c o m // we can NOT use it. if (length > inputArrayLength) { inputArrayLength = length; inputArray = new byte[length]; this.inputArray = inputArray; } else { inputArray = this.inputArray; } objectOutputBuffer.getBytes(objectOutputBuffer.readerIndex(), inputArray, 0, length); inputOffset = 0; } ////////// compressing data // we ALWAYS compress our data stream -- because of how AES-GCM pads data out, the small input (that would result in a larger // output), will be negated by the increase in size by the encryption byte[] compressOutput = this.compressOutput; int maxLengthLengthOffset = 4; // length is never negative, so 4 is OK (5 means it's negative) int maxCompressedLength = compressor.maxCompressedLength(length); // add 4 so there is room to write the compressed size to the buffer int maxCompressedLengthWithOffset = maxCompressedLength + maxLengthLengthOffset; // lazy initialize the compression output buffer if (maxCompressedLengthWithOffset > compressOutputLength) { compressOutputLength = maxCompressedLengthWithOffset; compressOutput = new byte[maxCompressedLengthWithOffset]; this.compressOutput = compressOutput; } // LZ4 compress. output offset max 4 bytes to leave room for length of tempOutput data int compressedLength = compressor.compress(inputArray, inputOffset, length, compressOutput, maxLengthLengthOffset, maxCompressedLength); // bytes can now be written to, because our compressed data is stored in a temp array. final int lengthLength = OptimizeUtilsByteArray.intLength(length, true); // correct input. compression output is now encryption input inputArray = compressOutput; inputOffset = maxLengthLengthOffset - lengthLength; // now write the ORIGINAL (uncompressed) length to the front of the byte array. This is so we can use the FAST decompress version OptimizeUtilsByteArray.writeInt(inputArray, length, true, inputOffset); // correct length for encryption length = compressedLength + lengthLength; // +1 to +4 for the uncompressed size bytes /////// encrypting data. final long nextGcmSequence = connection.getNextGcmSequence(); // this is a threadlocal, so that we don't clobber other threads that are performing crypto on the same connection at the same time final ParametersWithIV cryptoParameters = connection.getCryptoParameters(); BigEndian.Long_.toBytes(nextGcmSequence, cryptoParameters.getIV(), 4); // put our counter into the IV final GCMBlockCipher aes = this.aesEngine; aes.reset(); aes.init(true, cryptoParameters); byte[] cryptoOutput; // lazy initialize the crypto output buffer int cryptoSize = length + 16; // from: aes.getOutputSize(length); // 'output' is the temp byte array if (cryptoSize > cryptoOutputLength) { cryptoOutputLength = cryptoSize; cryptoOutput = new byte[cryptoSize]; this.cryptoOutput = cryptoOutput; } else { cryptoOutput = this.cryptoOutput; } int encryptedLength = aes.processBytes(inputArray, inputOffset, length, cryptoOutput, 0); try { // authentication tag for GCM encryptedLength += aes.doFinal(cryptoOutput, encryptedLength); } catch (Exception e) { throw new IOException("Unable to AES encrypt the data", e); } // write out our GCM counter OptimizeUtilsByteBuf.writeLong(buffer, nextGcmSequence, true); // have to copy over the orig data, because we used the temp buffer buffer.writeBytes(cryptoOutput, 0, encryptedLength); }
From source file:dorkbox.network.pipeline.ByteBufInput.java
License:Apache License
/** * Returns true if enough bytes are available to read an int with {@link #readInt(boolean)}. */// ww w . j a v a 2 s . c om @Override public boolean canReadInt() throws KryoException { ByteBuf buffer = byteBuf; int limit = buffer.writerIndex(); if (limit - buffer.readerIndex() >= 5) { return true; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } return true; }
From source file:dorkbox.network.pipeline.ByteBufInput.java
License:Apache License
/** * Returns true if enough bytes are available to read a long with {@link #readLong(boolean)}. *//*from w w w . java 2 s.c o m*/ @Override public boolean canReadLong() throws KryoException { ByteBuf buffer = byteBuf; int limit = buffer.writerIndex(); if (limit - buffer.readerIndex() >= 9) { return true; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } if ((buffer.readByte() & 0x80) == 0) { return true; } if (buffer.readerIndex() == limit) { return false; } return true; }
From source file:dorkbox.network.pipeline.ByteBufOutput.java
License:Apache License
public final void setBuffer(ByteBuf byteBuf) { this.byteBuf = byteBuf; if (byteBuf != null) { this.byteBuf.readerIndex(0); startIndex = byteBuf.writerIndex(); } else {/*from ww w . ja va2s. c o m*/ startIndex = 0; } }
From source file:dorkbox.network.pipeline.ByteBufOutput.java
License:Apache License
/** Writes the length and string, or null. Short strings are checked and if ASCII they are written more efficiently, else they * are written as UTF8. If a string is known to be ASCII, {@link #writeAscii(String)} may be used. The string can be read using * {@link ByteBufInput#readString()} or {@link ByteBufInput#readStringBuilder()}. * @param value May be null. *///w w w . ja v a 2s . c o m @Override public void writeString(String value) throws KryoException { if (value == null) { writeByte(0x80); // 0 means null, bit 8 means UTF8. return; } int charCount = value.length(); if (charCount == 0) { writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8. return; } // Detect ASCII. boolean ascii = false; if (charCount > 1 && charCount < 64) { // only snoop 64 chars in ascii = true; for (int i = 0; i < charCount; i++) { int c = value.charAt(i); if (c > 127) { ascii = false; break; } } } ByteBuf buffer = byteBuf; if (buffer.writableBytes() < charCount) { buffer.capacity(buffer.capacity() + charCount + 1); } if (!ascii) { writeUtf8Length(charCount + 1); } int charIndex = 0; // Try to write 8 bit chars. for (; charIndex < charCount; charIndex++) { int c = value.charAt(charIndex); if (c > 127) { break; // whoops! detect ascii. have to continue with a slower method! } buffer.writeByte((byte) c); } if (charIndex < charCount) { writeString_slow(value, charCount, charIndex); } else if (ascii) { // specify it's ASCII int i = buffer.writerIndex() - 1; buffer.setByte(i, buffer.getByte(i) | 0x80); // Bit 8 means end of ASCII. } }
From source file:dorkbox.network.pipeline.ByteBufOutput.java
License:Apache License
/** Writes a string that is known to contain only ASCII characters. Non-ASCII strings passed to this method will be corrupted. * Each byte is a 7 bit character with the remaining byte denoting if another character is available. This is slightly more * efficient than {@link #writeString(String)}. The string can be read using {@link ByteBufInput#readString()} or * {@link ByteBufInput#readStringBuilder()}. * @param value May be null. *//*from w ww .j a v a 2s . c o m*/ @Override public void writeAscii(String value) throws KryoException { if (value == null) { writeByte(0x80); // 0 means null, bit 8 means UTF8. return; } int charCount = value.length(); if (charCount == 0) { writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8. return; } ByteBuf buffer = byteBuf; if (buffer.writableBytes() < charCount) { buffer.capacity(buffer.capacity() + charCount + 1); } int charIndex = 0; // Try to write 8 bit chars. for (; charIndex < charCount; charIndex++) { int c = value.charAt(charIndex); buffer.writeByte((byte) c); } // specify it's ASCII int i = buffer.writerIndex() - 1; buffer.setByte(i, buffer.getByte(i) | 0x80); // Bit 8 means end of ASCII. }