aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuuta Liang <yuutaw@student.cs.ubc.ca>2023-11-23 08:41:56 +0800
committerYuuta Liang <yuutaw@student.cs.ubc.ca>2023-11-23 08:41:56 +0800
commit4d903cf80c4f2f8a5d6b22964ed23d8584fdbed4 (patch)
tree2ff4361e31afe6c4685511fc8ff90d090af13bf6
parent1f60e26c8023eed7205fb4c7ded2dc0eea6b6d57 (diff)
downloadjca-4d903cf80c4f2f8a5d6b22964ed23d8584fdbed4.tar
jca-4d903cf80c4f2f8a5d6b22964ed23d8584fdbed4.tar.gz
jca-4d903cf80c4f2f8a5d6b22964ed23d8584fdbed4.tar.bz2
jca-4d903cf80c4f2f8a5d6b22964ed23d8584fdbed4.zip
Add QR code
Signed-off-by: Yuuta Liang <yuutaw@student.cs.ubc.ca>
-rw-r--r--README.md3
-rw-r--r--src/main/ui/MainUI.java16
-rw-r--r--src/main/ui/widgets/QRPanel.java77
3 files changed, 95 insertions, 1 deletions
diff --git a/README.md b/README.md
index 1040e4b..802448a 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,9 @@ container, upon each successful sign.
8. Periodically publish CRLs. On the "CA" tab, click on the "CRL" button on the top right, and select a path for the CRL.
The database automatically saves after issuing a new CRL.
+The CA public key will also be rendered as a QR code on the "CA" tab, for easier transfer between computers. The encoded
+data is PEM-encoded PKCS#1 public key.
+
## Author
Yuuta Liang <yuutaw@student.ubc.ca>
diff --git a/src/main/ui/MainUI.java b/src/main/ui/MainUI.java
index 9637d79..34cc224 100644
--- a/src/main/ui/MainUI.java
+++ b/src/main/ui/MainUI.java
@@ -92,6 +92,7 @@ public class MainUI extends JFrame {
private final JButton buttonGenPrivKey = btn("Generate", 'G', this::onGeneratePrivateKey);
private final JButton buttonInstallCA = btn("Install", 'I', this::onInstallCA);
private final JButton buttonGenCSR = btn("CSR", this::onSignCSR);
+ private final QRPanel panelQR = new QRPanel(256);
private final JToolBar toolbarCA = new JToolBar();
private final JButton buttonCAToolbarCRL = btn("CRL", "publisher.png", this::onCRL);
@@ -192,6 +193,17 @@ public class MainUI extends JFrame {
renderRefresh();
}
+ /**
+ * EFFECTS: Set the QR code data to either null (no public key) or PEM-encoded PKCS#1 public key.
+ */
+ private void renderQRPublicKey() {
+ if (ca.getPublicKey() == null) {
+ panelQR.setData(null);
+ return;
+ }
+ panelQR.setData(Utils.toPEM(Utils.byteToByte(ca.getPublicKey().getEncoded()), "PUBLIC KEY"));
+ }
+
// -----END HELPER METHODS-----
// -----BEGIN DATA OBSERVERS-----
@@ -327,7 +339,8 @@ public class MainUI extends JFrame {
panelTabCA.add(buttonGenPrivKey, new GCBuilder().gridXY(1, 1).fill(HORIZONTAL).build());
panelTabCA.add(buttonInstallCA, new GCBuilder().gridXY(1, 2).fill(HORIZONTAL).build());
panelTabCA.add(buttonGenCSR, new GCBuilder().gridXY(2, 2).fill(HORIZONTAL).build());
- panelTabCA.add(new JPanel(), new GCBuilder().gridXY(3, 3).expandXY().fill(BOTH).build());
+ panelTabCA.add(panelQR, new GCBuilder().gridY(3).fill(HORIZONTAL).build());
+ panelTabCA.add(new JPanel(), new GCBuilder().gridXY(4, 4).expandXY().fill(BOTH).build());
tabbedPane.addTab("Certs", panelCertsTab = defView(scrTbl(tableCerts), "No issued certs"));
tabbedPane.addTab("Templates", panelTmpTab = defView(scrTbl(tableTemplates), "No templates"));
@@ -339,6 +352,7 @@ public class MainUI extends JFrame {
* MODIFIES: this
*/
private void renderCAPage() {
+ renderQRPublicKey();
if (ca.getPublicKey() == null) {
labelPrivateKey.setText("Private key not installed");
} else {
diff --git a/src/main/ui/widgets/QRPanel.java b/src/main/ui/widgets/QRPanel.java
new file mode 100644
index 0000000..d72d0d0
--- /dev/null
+++ b/src/main/ui/widgets/QRPanel.java
@@ -0,0 +1,77 @@
+package ui.widgets;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Collections;
+
+import static com.google.zxing.EncodeHintType.ERROR_CORRECTION;
+import static com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.L;
+
+/**
+ * A fixed-size panel displaying a QR code.
+ */
+public class QRPanel extends JPanel {
+ private final int size;
+
+ private BitMatrix data;
+
+ /**
+ * EFFECTS: Init with the specific rectangular size. Min size = max size = preferred size.
+ */
+ public QRPanel(int size) {
+ super();
+ setSize(new Dimension(size, size));
+ setMaximumSize(new Dimension(size, size));
+ setMinimumSize(new Dimension(size, size));
+ setPreferredSize(new Dimension(size, size));
+ this.size = size;
+ }
+
+ /**
+ * EFFECTS: Draw the QR code. Leave white if no data is set.
+ * MODIFIES: this
+ */
+ @Override
+ protected void paintComponent(Graphics graphics) {
+ super.paintComponent(graphics);
+ graphics.setColor(Color.WHITE);
+ graphics.fillRect(0, 0, size, size);
+
+ if (data == null) {
+ return;
+ }
+
+ graphics.setColor(Color.BLACK);
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < size; j++) {
+ if (data.get(i, j)) {
+ graphics.fillRect(i, j, 1, 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * EFFECTS: Set data and repaint. Nullable.
+ * MODIFIES: this
+ */
+ public void setData(String data) {
+ if (data == null) {
+ this.data = null;
+ invalidate();
+ return;
+ }
+ try {
+ this.data = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size,
+ Collections.singletonMap(ERROR_CORRECTION, L));
+ } catch (WriterException e) {
+ e.printStackTrace();
+ }
+ invalidate();
+ }
+}