AES 256加密和解密Java

发布于 2025-01-21 04:22:14 字数 1547 浏览 2 评论 0原文

当我尝试解密已加密的Whit php的OGG文件时,我有问题

您好, “ nofollow noreferrer”> php crypt函数

我用java使用了此代码,但生成的文件是损坏的

public static String decrypt(String input, String key){
        byte[] bytes = Base64.getDecoder().decode(input);
        if(bytes.length < 17) {
            return null;
        }
        String result = null;
        //byte[] ivBytes = Arrays.copyOfRange(bytes, 0, 16);
        //byte[] contentBytes = Arrays.copyOfRange(bytes, 16, bytes.length);


        try {
            //Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            

            Key skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            // Set the appropriate size for mInitVec by Generating a New One
            AlgorithmParameters params = cipher.getParameters();
            byte[] mInitVec = params.getParameterSpec(IvParameterSpec.class).getIV();

            cipher.init(Cipher.DECRYPT_MODE, skey, new IvParameterSpec(mInitVec));
            byte[] decrypted = cipher.doFinal(bytes);
            
            String uploadedFileLocation = "C:\\test3.ogg";
            
            FileOutputStream fs = new FileOutputStream(new File(uploadedFileLocation));
            fs.write(decrypted);
            fs.close();
            
            result ="decrypted";
         
        } catch (
                Exception ex
        ) {
            System.out.println(ex.toString());
        }
        return result;
    }

Hello I have an issue when I trying to decrypt an Ogg file whit java that was encrypted whit PHP

this is the function that creates the encrypted file

PHP crypt function

I used this code with java but the generated file is corrupt

public static String decrypt(String input, String key){
        byte[] bytes = Base64.getDecoder().decode(input);
        if(bytes.length < 17) {
            return null;
        }
        String result = null;
        //byte[] ivBytes = Arrays.copyOfRange(bytes, 0, 16);
        //byte[] contentBytes = Arrays.copyOfRange(bytes, 16, bytes.length);


        try {
            //Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            

            Key skey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            // Set the appropriate size for mInitVec by Generating a New One
            AlgorithmParameters params = cipher.getParameters();
            byte[] mInitVec = params.getParameterSpec(IvParameterSpec.class).getIV();

            cipher.init(Cipher.DECRYPT_MODE, skey, new IvParameterSpec(mInitVec));
            byte[] decrypted = cipher.doFinal(bytes);
            
            String uploadedFileLocation = "C:\\test3.ogg";
            
            FileOutputStream fs = new FileOutputStream(new File(uploadedFileLocation));
            fs.write(decrypted);
            fs.close();
            
            result ="decrypted";
         
        } catch (
                Exception ex
        ) {
            System.out.println(ex.toString());
        }
        return result;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

能怎样 2025-01-28 04:22:14

TLDR:使用IV(初始化向量或有时Nonce)解密,主要是IV

,例如CBC(例如CBC),必须像加密一样使用相同的IV(键) 。此外,像CBC这样的块模式通常需要填充和取消数据,而PHP使用的OPENSL确实使用Java也支持但必须选择的“标准” PKCS5/7填充。

$ cat 71865785.php
<?php
  $data = "some test data";
  $cipher = "aes-256-cbc";
  $key = "reallyrealsekritreallyrealsekrit"; // for test only, real key should not be human-chosen
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
  echo base64_encode($iv)."\n".openssl_encrypt($data,$cipher,$key,0,$iv)."\n";
?>
$ php 71865785.php
LGQXy7XF8DHBilN4Kb8Xrg==
DWI/F97O5e/NGD2czp2OUA==
$ cat SO71865785.java
//nopackage
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;

public class SO71865785 /* decrypt from PHP */ {
  public static void main (String[] args) throws Exception {
    byte[] key = "reallyrealsekritreallyrealsekrit".getBytes("ASCII"); // for test only
    byte[] iv = Base64.getDecoder().decode("LGQXy7XF8DHBilN4Kb8Xrg==");
    byte[] ctext = Base64.getDecoder().decode("DWI/F97O5e/NGD2czp2OUA==");

    Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
    ciph.init (Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
    byte[] plain = ciph.doFinal(ctext);
    System.out.println ("len="+plain.length+":"+new String(plain,"ASCII"));
    // if non-ASCII chars are present must use encoding to match encrypting system which is not known
  }
}
$ javac SO71865785.java
$ java -cp . SO71865785
len=14:some test data

对于真实的应用程序,您当然不会使用硬编码数据(通常也不应该硬编码密钥),并且将PHP应用程序生成的数据传递给Java应用程序的数据的方法有所不同(很多!)。一种非uncommon的方法是将iv和ciphertext(最好也是Mac或auth标签)连接用于传输和/或存储,然后用两个arrays.copyofrange与代码分开在评论中,但是对于此演示,我只是base64-ed每件(openssl_encrypt已经完成了base64 base64)。

请注意,对于AES-256,密钥必须正好是32个字节(并且应该是任意字节,而不是人类可以识别的字符)。在php/openssl中,如果您提供的量低于要求的静音板,则具有零字节(又称nul),但java却没有。如果您在Java中的byte []过于简短,则可以方便地使用eg arrays.copyof(poorkey,32)将其方便地零。

TLDR: it's mostly the IV

For encryption modes like CBC that use an IV (initialization vector, or sometimes nonce) decryption must use the same IV (and key) as encryption did. In addition, a block mode like CBC generally requires padding and unpadding the data, and OpenSSL as used by PHP does so using the 'standard' PKCS5/7 padding which Java also supports but must select.

$ cat 71865785.php
<?php
  $data = "some test data";
  $cipher = "aes-256-cbc";
  $key = "reallyrealsekritreallyrealsekrit"; // for test only, real key should not be human-chosen
  $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
  echo base64_encode($iv)."\n".openssl_encrypt($data,$cipher,$key,0,$iv)."\n";
?>
$ php 71865785.php
LGQXy7XF8DHBilN4Kb8Xrg==
DWI/F97O5e/NGD2czp2OUA==
$ cat SO71865785.java
//nopackage
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;

public class SO71865785 /* decrypt from PHP */ {
  public static void main (String[] args) throws Exception {
    byte[] key = "reallyrealsekritreallyrealsekrit".getBytes("ASCII"); // for test only
    byte[] iv = Base64.getDecoder().decode("LGQXy7XF8DHBilN4Kb8Xrg==");
    byte[] ctext = Base64.getDecoder().decode("DWI/F97O5e/NGD2czp2OUA==");

    Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
    ciph.init (Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new IvParameterSpec(iv));
    byte[] plain = ciph.doFinal(ctext);
    System.out.println ("len="+plain.length+":"+new String(plain,"ASCII"));
    // if non-ASCII chars are present must use encoding to match encrypting system which is not known
  }
}
$ javac SO71865785.java
$ java -cp . SO71865785
len=14:some test data

For a real application of course you wouldn't use hardcoded data (and usually shouldn't hardcode key either) and the method of passing the data produced by the PHP app to the Java app varies (a lot!). One not-uncommon way is to concatenate the IV and ciphertext (and preferably a MAC or auth tag as well) for transmission and/or storage and then separate them with code like the two Arrays.copyOfRange you have in comments, but for this demo I simply base64-ed each piece (openssl_encrypt already does base64 by default).

Note for AES-256 the key must be exactly 32 bytes (and should be arbitrary bytes, not characters recognizable to a human). In PHP/OpenSSL if you provide less than required it silently pads with zero bytes (aka NUL), but Java does not; if you have a too-short byte[] in Java you can conveniently zero-pad it with e.g. Arrays.copyOf(poorkey,32).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文