1 package org.bouncycastle.util.io.pem; 2 3 import java.io.BufferedWriter; 4 import java.io.IOException; 5 import java.io.Writer; 6 import java.util.Iterator; 7 8 import org.bouncycastle.util.encoders.Base64; 9 10 /** 11 * A generic PEM writer, based on RFC 1421 12 */ 13 public class PemWriter 14 extends BufferedWriter 15 { 16 private static final int LINE_LENGTH = 64; 17 18 private final int nlLength; 19 private char[] buf = new char[LINE_LENGTH]; 20 21 /** 22 * Base constructor. 23 * 24 * @param out output stream to use. 25 */ PemWriter(Writer out)26 public PemWriter(Writer out) 27 { 28 super(out); 29 30 String nl = System.getProperty("line.separator"); 31 if (nl != null) 32 { 33 nlLength = nl.length(); 34 } 35 else 36 { 37 nlLength = 2; 38 } 39 } 40 41 /** 42 * Return the number of bytes or characters required to contain the 43 * passed in object if it is PEM encoded. 44 * 45 * @param obj pem object to be output 46 * @return an estimate of the number of bytes 47 */ getOutputSize(PemObject obj)48 public int getOutputSize(PemObject obj) 49 { 50 // BEGIN and END boundaries. 51 int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4; 52 53 if (!obj.getHeaders().isEmpty()) 54 { 55 for (Iterator it = obj.getHeaders().iterator(); it.hasNext();) 56 { 57 PemHeader hdr = (PemHeader)it.next(); 58 59 size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength; 60 } 61 62 size += nlLength; 63 } 64 65 // base64 encoding 66 int dataLen = ((obj.getContent().length + 2) / 3) * 4; 67 68 size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength); 69 70 return size; 71 } 72 writeObject(PemObjectGenerator objGen)73 public void writeObject(PemObjectGenerator objGen) 74 throws IOException 75 { 76 PemObject obj = objGen.generate(); 77 78 writePreEncapsulationBoundary(obj.getType()); 79 80 if (!obj.getHeaders().isEmpty()) 81 { 82 for (Iterator it = obj.getHeaders().iterator(); it.hasNext();) 83 { 84 PemHeader hdr = (PemHeader)it.next(); 85 86 this.write(hdr.getName()); 87 this.write(": "); 88 this.write(hdr.getValue()); 89 this.newLine(); 90 } 91 92 this.newLine(); 93 } 94 95 writeEncoded(obj.getContent()); 96 writePostEncapsulationBoundary(obj.getType()); 97 } 98 writeEncoded(byte[] bytes)99 private void writeEncoded(byte[] bytes) 100 throws IOException 101 { 102 bytes = Base64.encode(bytes); 103 104 for (int i = 0; i < bytes.length; i += buf.length) 105 { 106 int index = 0; 107 108 while (index != buf.length) 109 { 110 if ((i + index) >= bytes.length) 111 { 112 break; 113 } 114 buf[index] = (char)bytes[i + index]; 115 index++; 116 } 117 this.write(buf, 0, index); 118 this.newLine(); 119 } 120 } 121 writePreEncapsulationBoundary( String type)122 private void writePreEncapsulationBoundary( 123 String type) 124 throws IOException 125 { 126 this.write("-----BEGIN " + type + "-----"); 127 this.newLine(); 128 } 129 writePostEncapsulationBoundary( String type)130 private void writePostEncapsulationBoundary( 131 String type) 132 throws IOException 133 { 134 this.write("-----END " + type + "-----"); 135 this.newLine(); 136 } 137 } 138