[ 
https://issues.apache.org/jira/browse/COMPRESS-633?focusedWorklogId=830650&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-830650
 ]

ASF GitHub Bot logged work on COMPRESS-633:
-------------------------------------------

                Author: ASF GitHub Bot
            Created on: 02/Dec/22 13:59
            Start Date: 02/Dec/22 13:59
    Worklog Time Spent: 10m 
      Work Description: garydgregory commented on code in PR #332:
URL: https://github.com/apache/commons-compress/pull/332#discussion_r1038170771


##########
src/main/java/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java:
##########
@@ -126,4 +115,109 @@ public void close() throws IOException {
             }
         };
     }
+
+    @Override
+    OutputStream encode(OutputStream out, Object options) throws IOException {
+        final AES256Options opts = (AES256Options) options;
+
+        return new OutputStream() {
+            private final CipherOutputStream cipherOutputStream = new 
CipherOutputStream(out, opts.getCipher());
+
+            // Ensures that data are encrypt in respect of cipher block size 
and pad with '0' if smaller
+            // NOTE: As "AES/CBC/PKCS5Padding" is weak and should not be used, 
we use "AES/CBC/NoPadding" with this
+            // manual implementation for padding possible thanks to the size 
of the file stored separately
+            private final int cipherBlockSize = 
opts.getCipher().getBlockSize();
+            private final byte[] cipherBlockBuffer = new byte[cipherBlockSize];
+            private int count = 0;
+
+            @Override
+            public void write(int b) throws IOException {
+                cipherBlockBuffer[count++] = (byte) b;
+                if (count == cipherBlockSize) {
+                    flushBuffer();
+                }
+            }
+
+            @Override
+            public void write(byte[] b, int off, int len) throws IOException {
+                int gap = len + count > cipherBlockSize ? cipherBlockSize - 
count : len;
+                System.arraycopy(b, off, cipherBlockBuffer, count, gap);
+                count += gap;
+
+                if (count == cipherBlockSize) {
+                    flushBuffer();
+
+                    if (len - gap >= cipherBlockSize) {
+                        // skip buffer to encrypt data chunks big enought to 
fit cipher block size
+                        int multipleCipherBlockSizeLen = (len - gap) / 
cipherBlockSize * cipherBlockSize;
+                        cipherOutputStream.write(b, off + gap, 
multipleCipherBlockSizeLen);
+                        gap += multipleCipherBlockSizeLen;
+                    }
+                    System.arraycopy(b, off + gap, cipherBlockBuffer, 0, len - 
gap);
+                    count = len - gap;
+                }
+            }
+
+            private void flushBuffer() throws IOException {
+                cipherOutputStream.write(cipherBlockBuffer);
+                count = 0;
+                Arrays.fill(cipherBlockBuffer, (byte) 0);
+            }
+
+            @Override
+            public void flush() throws IOException {
+                cipherOutputStream.flush();
+            }
+
+            @Override
+            public void close() throws IOException {
+                if (count > 0) {
+                    cipherOutputStream.write(cipherBlockBuffer);
+                }
+                cipherOutputStream.close();
+            }
+        };
+    }
+
+    static byte[] sha256Password(final byte[] password, final int 
numCyclesPower, final byte[] salt) {
+        final MessageDigest digest;
+        try {
+            digest = MessageDigest.getInstance("SHA-256");
+        } catch (final NoSuchAlgorithmException noSuchAlgorithmException) {
+            throw new IllegalStateException("SHA-256 is unsupported by your 
Java implementation", noSuchAlgorithmException);
+        }
+        final byte[] extra = new byte[8];
+        for (long j = 0; j < (1L << numCyclesPower); j++) {
+            digest.update(salt);
+            digest.update(password);
+            digest.update(extra);
+            for (int k = 0; k < extra.length; k++) {
+                ++extra[k];
+                if (extra[k] != 0) {
+                    break;
+                }
+            }
+        }
+        return digest.digest();
+    }
+
+    @Override
+    byte[] getOptionsAsProperties(Object options) throws IOException {
+        AES256Options opts = (AES256Options) options;

Review Comment:
   Use final where you can.





Issue Time Tracking
-------------------

    Worklog Id:     (was: 830650)
    Time Spent: 0.5h  (was: 20m)

> Adding support for SevenZ password encryption
> ---------------------------------------------
>
>                 Key: COMPRESS-633
>                 URL: https://issues.apache.org/jira/browse/COMPRESS-633
>             Project: Commons Compress
>          Issue Type: Improvement
>          Components: Compressors
>    Affects Versions: 1.22
>            Reporter: Daniel Santos
>            Priority: Major
>              Labels: contributing, features
>          Time Spent: 0.5h
>  Remaining Estimate: 0h
>
> 👉🏼 The purpose is to provide password based encryption for 7z compression in 
> the same way of decryption already supported, so go forward of [one know 
> limitation|https://commons.apache.org/proper/commons-compress/limitations.html]
> ☝️In this way, I would like to submit my contribution based on the existing 
> implementation of decryption and the [C++ implementation of 7z 
> |https://github.com/kornelski/7z/blob/main/CPP/7zip/Crypto/7zAes.cpp]
> ✅ I added one unit test
>  
> I prepared a [Pull Request on 
> GitHub|https://github.com/apache/commons-compress/pull/332]
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to