1

サンプル MP3 ファイルをクライアント Flash Player (SWF) に提供する asp.net Web サイトがあります。

これらのファイルは、多数のダウンロード ツールでダウンロードできます。

登録メンバーのみが高品質の mp3 サンプルにアクセスできますが、クライアントはこれらの低品質の MP3 ファイルがダウンロード ツールによってダウンロードされるのを防ぎたいと考えています。

だから私はこの解決策について考えました:

  1. これらの MP3 ファイルをサーバー側 (ASP.NET) で bytearray に変換します。
  2. ビット単位の XOR 操作を実行する (単純な暗号化)
  3. この配列を aspx の応答ストリームに書き込みます
  4. この新しいファイル/ページ/aspx を要求するように Flash (.fla) を変更します。
  5. Flash でビット単位の XOR 演算を実行し、バイト配列として元の MP3 に変換します。(簡易復号化)
  6. MP3 を再生する

手順 6 までは成功しました。このバイト配列を、Flash で再生できる Sound オブジェクトに変換できません。フラッシュ上の結果配列と ASP.NET 上のソース配列を少しずつ比較しました。それらは等しいです。

私は完全に異なるアプローチに対してオープンです。しかし、Flash Media Server を使用できません。Flash as3 と ASP.NET を使用する必要があります。

また、非常に重要です!.mp3 をダウンロード/復号化し、非同期で再生する必要があります (これは成功しませんでした)。

4

5 に答える 5

3

ファイルへのアクセスを制限するには、おそらく認証が最も簡単な方法であるという Peter Elliot の意見に同意します。ただし、ファイルの暗号化のルートをまだ調査する必要がある場合は、Alex Vlad の回答を少し拡張すると思いました。

オーディオ ファイルをストリーミングし、オンザフライで復号化し、非同期で再生できるようにするために必要なことは、クラス ( docs ) をクラス ( docs ) と組み合わせて使用​​し部分URLStreamダウンロードされたファイルのバッファーを保持することです。コンテンツ。Sound

説明する擬似コード:

class AsyncEncryptedSoundPlayer extends Sound {
    var buffer:ByteArray;
    var stream:URLStream;
    var currSoundPosition:uint = 0;

    public function AsyncEncryptedSoundPlayer(url:String) {
        buffer = new ByteArray();
        stream = new URLStream();
        stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
        stream.load(new URLRequest(url));

        addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataRequested);
    }

    function onProgress(e:ProgressEvent):void {
        var tmpData:ByteArray;
        stream.readBytes(tmpData, buffer.length, stream.bytesAvailable - buffer.length);
        var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
        buffer.writeBytes(decryptedData, buffer.length, decryptedData.length); // Add decrypted data to buffer
    }

    function onSampleDataRequested(e:ProgressEvent):void {
        // Feed samples from the buffer to the Sound instance
        // You may have to pause the audio to increase the buffer it the download speed isn't high enough
        event.data.writeBytes(buffer, currSoundPosition, 2048);
        currSoundPosition += 2048;
    }

    function decryptedData(data:ByteArray):void {
        // Returns decrypted data
    }
}

これは明らかにクラスの大まかな概要ですが、正しい方向に向けられることを願っています。

于 2013-01-30T00:09:17.967 に答える
2

@walkietokyo、正しい方向に向けてくれてありがとう。やりたいことをやり遂げることに成功しました。ここでのキーワードはloadCompressedDataFromByteArray関数でした。

数十回の試行錯誤の後、私はそれloadCompressedDataFromByteArrayが異なる方法で機能していることを発見しました。

変換したものはすべて、サウンド オブジェクトデータの末尾に追加します。

loadCompressedDataFromByteArray別の問題: サウンド オブジェクトは、そのplay関数が呼び出された後、追加された部分を再生し続けません。

そこで、一種のダブル バッファリングを実装しました。2 つのサウンド オブジェクトを同じ意味で使用します。

私の最終(テスト)バージョンを以下に示します。私が使用した暗号化 (難読化) 方法 (単純な XOR) では、テストしたダウンロード マネージャー、グラバー、スニファーはいずれも Mp3 を再生できませんでした。

フラッシュ (クライアント) 側:

import flash.events.DataEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.OutputProgressEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.utils.ByteArray;
import flashx.textLayout.formats.Float;

var buffer:ByteArray;
var stream:URLStream;
var bufferReadPosition:uint = 0;
var bufferWritePosition:uint = 0;

var url:String = "http://www.blablabla.com/MusicServer.aspx?" + (new Date());

buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));

var s1:Sound = new Sound();
var s2:Sound = new Sound();

var channel1:SoundChannel;
var channel2:SoundChannel;

var pausePosition:int = 0;

var aSoundIsPlaying:Boolean = false;

var lastLoadedS1:Boolean = false;

var lastS1Length:int = 0;
var lastS2Length:int = 0;

function onProgress(e:ProgressEvent):void {
    var tmpData:ByteArray = new ByteArray();

    stream.readBytes(tmpData, 0, stream.bytesAvailable);

    var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data

    buffer.position = bufferWritePosition;
    buffer.writeBytes(decryptedData, 0, decryptedData.length); // Add decrypted data to buffer
    bufferWritePosition += decryptedData.length;

    if(lastLoadedS1)
    {
        buffer.position = lastS2Length;
        s2.loadCompressedDataFromByteArray(buffer, buffer.length - lastS2Length);
        lastS2Length = buffer.length;
    }
    else
    {
        buffer.position = lastS1Length;
        s1.loadCompressedDataFromByteArray(buffer, buffer.length - lastS1Length);
        lastS1Length = buffer.length;
    }

    if(!aSoundIsPlaying)
    {
        DecidePlay();
    }
}

function channel1Completed(e:Event):void
{
    DecidePlay();
}

function channel2Completed(e:Event):void
{
    DecidePlay();
}

function DecidePlay():void
{
    aSoundIsPlaying = false;

    if(lastLoadedS1)
    {
        channel1.stop();

        if(s2.length - s1.length > 10000)
        {
            //At least a 10 second buffer
            channel2 = s2.play(s1.length);
            channel2.addEventListener(Event.SOUND_COMPLETE, channel2Completed);
            lastLoadedS1 = false;
            aSoundIsPlaying = true;
        }
    }
    else
    {
        if(channel2 != null)
        {
            channel2.stop();
        }

        if(s1.length - s2.length > 10000)
        {
            //At least a 10 second buffer
            channel1 = s1.play(s2.length);
            channel1.addEventListener(Event.SOUND_COMPLETE, channel1Completed);
            lastLoadedS1 = true;
            aSoundIsPlaying = true;
        }
    }
}

function decryptData(data:ByteArray):ByteArray {
    for(var i:int = 0;i<data.length;i++)
    {
        //Here put in your bitwise decryption code
    }
    return data;
}

ASP.NET サーバー側 (MusicServer.aspx):

    protected void Page_Load(object sender, EventArgs e)
    {
        CopyStream(Mp3ToStream(Server.MapPath("blabla.mp3")), Response.OutputStream);

        this.Response.AddHeader("Content-Disposition", "blabla.mp3");
        this.Response.ContentType = "audio/mpeg";
        this.Response.End();
    }

    public static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[32768];
        int read;
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            for (int i = 0; i < read; i++)
            {
                //Here put in your bitwise encryption code
            }

            output.Write(buffer, 0, read);
        }
    }

    public Stream Mp3ToStream(string filePath)
    {
        using (FileStream fileStream = File.OpenRead(filePath))
        {
            MemoryStream memStream = new MemoryStream();
            memStream.SetLength(fileStream.Length);
            fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
            return memStream;
        }
    }
于 2013-01-30T18:39:17.923 に答える
1

サービスから返されるデータを暗号化するよりも簡単なのは、代わりにリクエストを認証して、swf だけがファイルをリクエストできるようにすることです。

これは、Amazon API が機能するのと同じ方法で実現できます。つまり、タイムスタンプを含む多数のパラメーターを含むリクエストを作成します。これらすべての引数を HMAC (HMAC-SHA256 はas3crypto ライブラリで利用可能) でまとめて、swf に埋め込まれた秘密鍵と共にハッシュします。サーバー側はこのリクエストを認証し、ハッシュが有効であり、タイムスタンプに十分近いことを確認します。ハッシュが不適切なリクエスト、または過去のタイムスタンプを使用したリクエスト (リプレイ攻撃) は拒否されます。

これは確かに完全なセキュリティではありません。やる気のあるユーザーであれば、swf を逆アセンブルして認証キーを引き出したり、ブラウザのキャッシュから mp3 を取得したりできます。しかし、繰り返しになりますが、使用するメカニズムにはこれらの問題があります。これにより、すべてのファイルを暗号化および復号化するオーバーヘッドがなくなり、代わりに作業がリクエスト生成フェーズに移行されます。

于 2013-01-29T14:40:04.250 に答える
0

こちらをご覧ください:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/SampleDataEvent.html

そしてここ:

http://help.adobe.com/en_US/as3/dev/WSE523B839-C626-4983-B9C0-07CF1A087ED7.html

于 2013-01-29T14:36:55.690 に答える
0

FlashSoundはストリーミング mp3 再生のみをサポートします。つまり、直接リンクで mp3 のみを再生できます。ただし、mp3 が埋め込まれた swf ファイルを送信することはできます。この swf は、mp3 を暗号化するのと同じ方法で暗号化できます。

mp3 を埋め込んで使用するための as3 コード:

public class Sounds
{
    [Embed(source="/../assets/sounds/sound1.mp3")]
    private static const sound1:Class;
}

この swf をロードした後Loader、次の方法でサウンドにアクセスできます。

var domain:ApplicationDomain = ApplicationDomain.currentDomain; // <-- ApplicationDomain where you load sounds.swf
var soundClass:Class = domain.getDefinition("Sounds_sound1");
var sound:Sound = new soundClass();
sound.play();

必ず、次の少なくとも 1 つを実行してください。

  • サウンド クラスに別の名前を付けます ( sound1)
  • ホルダー クラスに別の名前を付ける ( Sounds)
  • または異なるアプリケーション ドメインに sound.swf をロードする

クラス名が重複しないようにします。

残念ながら、このアプローチではサウンドをストリーミング再生することはできません。swf 全体をロードして復号化する必要があり、その後で初めてサウンドを再生できるようになります。

于 2013-01-29T12:38:21.927 に答える